vibe-slides

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Vibe Slides

Vibe Slides

Create zero-dependency, animation-rich HTML presentations that run entirely in the browser. This skill helps non-designers discover their preferred aesthetic through visual exploration ("show, don't tell"), then generates production-quality slide decks.
创建零依赖、富动画效果的HTML演示文稿,可完全在浏览器中运行。该技能帮助非设计人员通过视觉探索(“展示而非说教”)找到自己偏好的美学风格,然后生成可用于生产环境的幻灯片。

Core Philosophy

核心理念

  1. Zero Dependencies — Single HTML files with inline CSS/JS. No npm, no build tools.
  2. Show, Don't Tell — People don't know what they want until they see it. Generate visual previews, not abstract choices.
  3. Distinctive Design — Avoid generic "AI slop" aesthetics. Every presentation should feel custom-crafted.
  4. Production Quality — Code should be well-commented, accessible, and performant.
  5. Viewport Fitting (CRITICAL) — Every slide MUST fit exactly within the viewport. No scrolling within slides, ever. This is non-negotiable.

  1. 零依赖 — 包含内联CSS/JS的单个HTML文件。无需npm,无需构建工具。
  2. 展示而非说教 — 人们在看到之前不知道自己想要什么。生成视觉预览,而非抽象选项。
  3. 独特设计 — 避免通用的“AI生成式”美学风格。每个演示文稿都应感觉是定制打造的。
  4. 生产环境级质量 — 代码应注释完善、易于访问且性能优异。
  5. 视口适配(至关重要) — 每张幻灯片必须完全适配视口。幻灯片内绝不允许出现滚动。这是不可协商的要求。

CRITICAL: Viewport Fitting Requirements

至关重要:视口适配要求

This section is mandatory for ALL presentations. Every slide must be fully visible without scrolling on any screen size.
本节适用于所有演示文稿。每张幻灯片在任何屏幕尺寸下都必须无需滚动即可完全显示。

The Golden Rule

黄金法则

Each slide = exactly one viewport height (100vh/100dvh)
Content overflows? → Split into multiple slides or reduce content
Never scroll within a slide.
每张幻灯片 = 恰好一个视口高度(100vh/100dvh)
内容溢出? → 拆分为多张幻灯片或精简内容
绝不允许幻灯片内出现滚动。

Content Density Limits

内容密度限制

To guarantee viewport fitting, enforce these limits per slide:
Slide TypeMaximum Content
Title slide1 heading + 1 subtitle + optional tagline
Content slide1 heading + 4-6 bullet points OR 1 heading + 2 paragraphs
Feature grid1 heading + 6 cards maximum (2x3 or 3x2 grid)
Code slide1 heading + 8-10 lines of code maximum
Quote slide1 quote (max 3 lines) + attribution
Image slide1 heading + 1 image (max 60vh height)
If content exceeds these limits → Split into multiple slides
为确保视口适配,每张幻灯片需遵循以下内容限制:
幻灯片类型最大内容量
标题页1个主标题 + 1个副标题 + 可选标语
内容页1个标题 + 4-6个项目符号 或 1个标题 + 2段文字
功能网格1个标题 + 最多6个卡片(2x3或3x2网格)
代码页1个标题 + 最多8-10行代码
引用页1条引用(最多3行) + 署名
图片页1个标题 + 1张图片(最大高度60vh)
如果内容超出限制 → 拆分为多张幻灯片

Required CSS Architecture

必需的CSS架构

Every presentation MUST include this base CSS for viewport fitting:
css
/* ===========================================
   VIEWPORT FITTING: MANDATORY BASE STYLES
   These styles MUST be included in every presentation.
   They ensure slides fit exactly in the viewport.
   =========================================== */

/* 1. Lock html/body to viewport */
html, body {
    height: 100%;
    overflow-x: hidden;
}

html {
    scroll-snap-type: y mandatory;
    scroll-behavior: smooth;
}

/* 2. Each slide = exact viewport height */
.slide {
    width: 100vw;
    height: 100vh;
    height: 100dvh; /* Dynamic viewport height for mobile browsers */
    overflow: hidden; /* CRITICAL: Prevent ANY overflow */
    scroll-snap-align: start;
    display: flex;
    flex-direction: column;
    position: relative;
}

/* 3. Content container with flex for centering */
.slide-content {
    flex: 1;
    display: flex;
    flex-direction: column;
    justify-content: center;
    max-height: 100%;
    overflow: hidden; /* Double-protection against overflow */
    padding: var(--slide-padding);
}

/* 4. ALL typography uses clamp() for responsive scaling */
:root {
    /* Titles scale from mobile to desktop */
    --title-size: clamp(1.5rem, 5vw, 4rem);
    --h2-size: clamp(1.25rem, 3.5vw, 2.5rem);
    --h3-size: clamp(1rem, 2.5vw, 1.75rem);

    /* Body text */
    --body-size: clamp(0.75rem, 1.5vw, 1.125rem);
    --small-size: clamp(0.65rem, 1vw, 0.875rem);

    /* Spacing scales with viewport */
    --slide-padding: clamp(1rem, 4vw, 4rem);
    --content-gap: clamp(0.5rem, 2vw, 2rem);
    --element-gap: clamp(0.25rem, 1vw, 1rem);
}

/* 5. Cards/containers use viewport-relative max sizes */
.card, .container, .content-box {
    max-width: min(90vw, 1000px);
    max-height: min(80vh, 700px);
}

/* 6. Lists auto-scale with viewport */
.feature-list, .bullet-list {
    gap: clamp(0.4rem, 1vh, 1rem);
}

.feature-list li, .bullet-list li {
    font-size: var(--body-size);
    line-height: 1.4;
}

/* 7. Grids adapt to available space */
.grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(min(100%, 250px), 1fr));
    gap: clamp(0.5rem, 1.5vw, 1rem);
}

/* 8. Images constrained to viewport */
img, .image-container {
    max-width: 100%;
    max-height: min(50vh, 400px);
    object-fit: contain;
}

/* ===========================================
   RESPONSIVE BREAKPOINTS
   Aggressive scaling for smaller viewports
   =========================================== */

/* Short viewports (< 700px height) */
@media (max-height: 700px) {
    :root {
        --slide-padding: clamp(0.75rem, 3vw, 2rem);
        --content-gap: clamp(0.4rem, 1.5vw, 1rem);
        --title-size: clamp(1.25rem, 4.5vw, 2.5rem);
        --h2-size: clamp(1rem, 3vw, 1.75rem);
    }
}

/* Very short viewports (< 600px height) */
@media (max-height: 600px) {
    :root {
        --slide-padding: clamp(0.5rem, 2.5vw, 1.5rem);
        --content-gap: clamp(0.3rem, 1vw, 0.75rem);
        --title-size: clamp(1.1rem, 4vw, 2rem);
        --body-size: clamp(0.7rem, 1.2vw, 0.95rem);
    }

    /* Hide non-essential elements */
    .nav-dots, .keyboard-hint, .decorative {
        display: none;
    }
}

/* Extremely short (landscape phones, < 500px height) */
@media (max-height: 500px) {
    :root {
        --slide-padding: clamp(0.4rem, 2vw, 1rem);
        --title-size: clamp(1rem, 3.5vw, 1.5rem);
        --h2-size: clamp(0.9rem, 2.5vw, 1.25rem);
        --body-size: clamp(0.65rem, 1vw, 0.85rem);
    }
}

/* Narrow viewports (< 600px width) */
@media (max-width: 600px) {
    :root {
        --title-size: clamp(1.25rem, 7vw, 2.5rem);
    }

    /* Stack grids vertically */
    .grid {
        grid-template-columns: 1fr;
    }
}

/* ===========================================
   REDUCED MOTION
   Respect user preferences
   =========================================== */
@media (prefers-reduced-motion: reduce) {
    *, *::before, *::after {
        animation-duration: 0.01ms !important;
        transition-duration: 0.2s !important;
    }

    html {
        scroll-behavior: auto;
    }
}
每个演示文稿必须包含以下基础CSS以实现视口适配:
css
/* ===========================================
   VIEWPORT FITTING: MANDATORY BASE STYLES
   These styles MUST be included in every presentation.
   They ensure slides fit exactly in the viewport.
   =========================================== */

/* 1. Lock html/body to viewport */
html, body {
    height: 100%;
    overflow-x: hidden;
}

html {
    scroll-snap-type: y mandatory;
    scroll-behavior: smooth;
}

/* 2. Each slide = exact viewport height */
.slide {
    width: 100vw;
    height: 100vh;
    height: 100dvh; /* Dynamic viewport height for mobile browsers */
    overflow: hidden; /* CRITICAL: Prevent ANY overflow */
    scroll-snap-align: start;
    display: flex;
    flex-direction: column;
    position: relative;
}

/* 3. Content container with flex for centering */
.slide-content {
    flex: 1;
    display: flex;
    flex-direction: column;
    justify-content: center;
    max-height: 100%;
    overflow: hidden; /* Double-protection against overflow */
    padding: var(--slide-padding);
}

/* 4. ALL typography uses clamp() for responsive scaling */
:root {
    /* Titles scale from mobile to desktop */
    --title-size: clamp(1.5rem, 5vw, 4rem);
    --h2-size: clamp(1.25rem, 3.5vw, 2.5rem);
    --h3-size: clamp(1rem, 2.5vw, 1.75rem);

    /* Body text */
    --body-size: clamp(0.75rem, 1.5vw, 1.125rem);
    --small-size: clamp(0.65rem, 1vw, 0.875rem);

    /* Spacing scales with viewport */
    --slide-padding: clamp(1rem, 4vw, 4rem);
    --content-gap: clamp(0.5rem, 2vw, 2rem);
    --element-gap: clamp(0.25rem, 1vw, 1rem);
}

/* 5. Cards/containers use viewport-relative max sizes */
.card, .container, .content-box {
    max-width: min(90vw, 1000px);
    max-height: min(80vh, 700px);
}

/* 6. Lists auto-scale with viewport */
.feature-list, .bullet-list {
    gap: clamp(0.4rem, 1vh, 1rem);
}

.feature-list li, .bullet-list li {
    font-size: var(--body-size);
    line-height: 1.4;
}

/* 7. Grids adapt to available space */
.grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(min(100%, 250px), 1fr));
    gap: clamp(0.5rem, 1.5vw, 1rem);
}

/* 8. Images constrained to viewport */
img, .image-container {
    max-width: 100%;
    max-height: min(50vh, 400px);
    object-fit: contain;
}

/* ===========================================
   RESPONSIVE BREAKPOINTS
   Aggressive scaling for smaller viewports
   =========================================== */

/* Short viewports (< 700px height) */
@media (max-height: 700px) {
    :root {
        --slide-padding: clamp(0.75rem, 3vw, 2rem);
        --content-gap: clamp(0.4rem, 1.5vw, 1rem);
        --title-size: clamp(1.25rem, 4.5vw, 2.5rem);
        --h2-size: clamp(1rem, 3vw, 1.75rem);
    }
}

/* Very short viewports (< 600px height) */
@media (max-height: 600px) {
    :root {
        --slide-padding: clamp(0.5rem, 2.5vw, 1.5rem);
        --content-gap: clamp(0.3rem, 1vw, 0.75rem);
        --title-size: clamp(1.1rem, 4vw, 2rem);
        --body-size: clamp(0.7rem, 1.2vw, 0.95rem);
    }

    /* Hide non-essential elements */
    .nav-dots, .keyboard-hint, .decorative {
        display: none;
    }
}

/* Extremely short (landscape phones, < 500px height) */
@media (max-height: 500px) {
    :root {
        --slide-padding: clamp(0.4rem, 2vw, 1rem);
        --title-size: clamp(1rem, 3.5vw, 1.5rem);
        --h2-size: clamp(0.9rem, 2.5vw, 1.25rem);
        --body-size: clamp(0.65rem, 1vw, 0.85rem);
    }
}

/* Narrow viewports (< 600px width) */
@media (max-width: 600px) {
    :root {
        --title-size: clamp(1.25rem, 7vw, 2.5rem);
    }

    /* Stack grids vertically */
    .grid {
        grid-template-columns: 1fr;
    }
}

/* ===========================================
   REDUCED MOTION
   Respect user preferences
   =========================================== */
@media (prefers-reduced-motion: reduce) {
    *, *::before, *::after {
        animation-duration: 0.01ms !important;
        transition-duration: 0.2s !important;
    }

    html {
        scroll-behavior: auto;
    }
}

Overflow Prevention Checklist

溢出预防检查清单

Before generating any presentation, mentally verify:
  1. ✅ Every
    .slide
    has
    height: 100vh; height: 100dvh; overflow: hidden;
  2. ✅ All font sizes use
    clamp(min, preferred, max)
  3. ✅ All spacing uses
    clamp()
    or viewport units
  4. ✅ Content containers have
    max-height
    constraints
  5. ✅ Images have
    max-height: min(50vh, 400px)
    or similar
  6. ✅ Grids use
    auto-fit
    with
    minmax()
    for responsive columns
  7. ✅ Breakpoints exist for heights: 700px, 600px, 500px
  8. ✅ No fixed pixel heights on content elements
  9. ✅ Content per slide respects density limits
在生成任何演示文稿之前,请在心里验证以下内容:
  1. ✅ 每个
    .slide
    都设置了
    height: 100vh; height: 100dvh; overflow: hidden;
  2. ✅ 所有字体大小使用
    clamp(min, preferred, max)
  3. ✅ 所有间距使用
    clamp()
    或视口单位
  4. ✅ 内容容器设置了
    max-height
    限制
  5. ✅ 图片设置了
    max-height: min(50vh, 400px)
    或类似限制
  6. ✅ 网格使用
    auto-fit
    配合
    minmax()
    实现响应式列
  7. ✅ 针对以下高度设置了断点:700px、600px、500px
  8. ✅ 内容元素没有固定像素高度
  9. ✅ 每张幻灯片的内容符合密度限制

When Content Doesn't Fit

当内容无法适配时

If you find yourself with too much content:
DO:
  • Split into multiple slides
  • Reduce bullet points (max 5-6 per slide)
  • Shorten text (aim for 1-2 lines per bullet)
  • Use smaller code snippets
  • Create a "continued" slide
DON'T:
  • Reduce font size below readable limits
  • Remove padding/spacing entirely
  • Allow any scrolling
  • Cram content to fit
如果你发现内容过多:
应该做:
  • 拆分为多张幻灯片
  • 减少项目符号(每张幻灯片最多5-6个)
  • 精简文字(每个项目符号目标1-2行)
  • 使用更短的代码片段
  • 创建“续页”幻灯片
不要做:
  • 将字体大小缩小到可读性以下
  • 完全移除内边距/间距
  • 允许任何滚动
  • 强行塞入内容

Testing Viewport Fit

视口适配测试

After generating, recommend the user test at these sizes:
  • Desktop: 1920×1080, 1440×900, 1280×720
  • Tablet: 1024×768, 768×1024 (portrait)
  • Mobile: 375×667, 414×896
  • Landscape phone: 667×375, 896×414

生成演示文稿后,建议用户在以下尺寸下测试:
  • 桌面端:1920×1080、1440×900、1280×720
  • 平板端:1024×768、768×1024(竖屏)
  • 移动端:375×667、414×896
  • 横屏手机:667×375、896×414

Phase 0: Detect Mode

阶段0:检测模式

First, determine what the user wants:
Mode A: New Presentation
  • User wants to create slides from scratch
  • Proceed to Phase 1 (Content Discovery)
Mode B: PPT Conversion
  • User has a PowerPoint file (.ppt, .pptx) to convert
  • Proceed to Phase 4 (PPT Extraction)
Mode C: Existing Presentation Enhancement
  • User has an HTML presentation and wants to improve it
  • Read the existing file, understand the structure, then enhance

首先,确定用户的需求:
模式A:新建演示文稿
  • 用户想要从零开始创建幻灯片
  • 进入阶段1(内容探索)
模式B:PPT转换
  • 用户有PowerPoint文件(.ppt、.pptx)需要转换
  • 进入阶段4(PPT提取)
模式C:现有演示文稿优化
  • 用户已有HTML演示文稿并想要改进
  • 读取现有文件,理解其结构,然后进行优化

Phase 1: Content Discovery (New Presentations)

阶段1:内容探索(新建演示文稿)

Before designing, understand the content. Ask via AskUserQuestion:
在设计之前,先了解内容。通过AskUserQuestion询问:

Step 1.1: Presentation Context

步骤1.1:演示文稿背景

Question 1: Purpose
  • Header: "Purpose"
  • Question: "What is this presentation for?"
  • Options:
    • "Pitch deck" — Selling an idea, product, or company to investors/clients
    • "Teaching/Tutorial" — Explaining concepts, how-to guides, educational content
    • "Conference talk" — Speaking at an event, tech talk, keynote
    • "Internal presentation" — Team updates, strategy meetings, company updates
Question 2: Slide Count
  • Header: "Length"
  • Question: "Approximately how many slides?"
  • Options:
    • "Short (5-10)" — Quick pitch, lightning talk
    • "Medium (10-20)" — Standard presentation
    • "Long (20+)" — Deep dive, comprehensive talk
Question 3: Content
  • Header: "Content"
  • Question: "Do you have the content ready, or do you need help structuring it?"
  • Options:
    • "I have all content ready" — Just need to design the presentation
    • "I have rough notes" — Need help organizing into slides
    • "I have a topic only" — Need help creating the full outline
If user has content, ask them to share it (text, bullet points, images, etc.).

问题1:用途
  • 标题:“用途”
  • 问题:“这份演示文稿用于什么场景?”
  • 选项:
    • “路演PPT” — 向投资者/客户推销想法、产品或公司
    • “教学/教程” — 讲解概念、操作指南、教育内容
    • “会议演讲” — 在活动、技术分享、主题演讲中使用
    • “内部演示” — 团队更新、战略会议、公司通报
问题2:幻灯片数量
  • 标题:“长度”
  • 问题:“大约需要多少张幻灯片?”
  • 选项:
    • “短(5-10张)” — 快速路演、闪电演讲
    • “中(10-20张)” — 标准演示文稿
    • “长(20张以上)” — 深度讲解、全面的演讲
问题3:内容准备情况
  • 标题:“内容”
  • 问题:“你已经准备好内容了,还是需要帮助梳理结构?”
  • 选项:
    • “我已准备好所有内容” — 只需要设计演示文稿
    • “我有粗略的笔记” — 需要帮助整理成幻灯片
    • “我只有主题” — 需要帮助创建完整的大纲
如果用户已有内容,请让他们分享(文字、项目符号、图片等)。

Phase 2: Style Discovery (Visual Exploration)

阶段2:风格探索(视觉探索)

CRITICAL: This is the "show, don't tell" phase.
Most people can't articulate design preferences in words. Instead of asking "do you want minimalist or bold?", we generate mini-previews and let them react.
至关重要:这是“展示而非说教”的阶段。
大多数人无法用语言清晰表达自己的设计偏好。与其问“你想要极简风格还是大胆风格?”,不如生成迷你预览让用户直观感受。

How Users Choose Presets

用户选择预设的方式

Users can select a style in two ways:
Option A: Guided Discovery (Default)
  • User answers mood questions
  • Skill generates 3 preview files based on their answers
  • User views previews in browser and picks their favorite
  • This is best for users who don't have a specific style in mind
Option B: Direct Selection
  • If user already knows what they want, they can request a preset by name
  • Example: "Use the Bold Signal style" or "I want something like Dark Botanical"
  • Skip to Phase 3 immediately
Available Presets:
PresetVibeBest ForTemplate?
ArchonDeep-tech cinematic + corporate polishProtocol/crypto, tech narratives, business decksYES
templates/archon/
Archon GridArchon + animated grid glow backgroundSame as Archon, with subtle animated grid effectYES
templates/archon-grid/
Bold SignalConfident, high-impactPitch decks, keynotesNo
Electric StudioClean, professionalAgency presentationsNo
Creative VoltageEnergetic, retro-modernCreative pitchesNo
Dark BotanicalElegant, sophisticatedPremium brandsNo
Notebook TabsEditorial, organizedReports, reviewsNo
Pastel GeometryFriendly, approachableProduct overviewsNo
Split PastelPlayful, modernCreative agenciesNo
Vintage EditorialWitty, personality-drivenPersonal brandsNo
Neon CyberFuturistic, techyTech startupsNo
Terminal GreenDeveloper-focusedDev tools, APIsNo
Swiss ModernMinimal, preciseCorporate, dataNo
Paper & InkLiterary, thoughtfulStorytellingNo
用户可以通过两种方式选择风格:
选项A:引导式探索(默认)
  • 用户回答关于氛围的问题
  • 技能根据回答生成3个预览文件
  • 用户在浏览器中查看预览并选择最喜欢的
  • 最适合没有特定风格想法的用户
选项B:直接选择
  • 如果用户已经知道自己想要什么,可以直接按名称请求预设
  • 示例:“使用Bold Signal风格”或“我想要类似Dark Botanical的风格”
  • 直接跳转到阶段3
可用预设:
预设氛围最佳适用场景是否有模板?
Archon深度科技电影感 + 企业精致感协议/加密货币、技术叙事、商务PPT
templates/archon/
Archon GridArchon + 动画网格发光背景与Archon相同,但增加了微妙的动画网格效果
templates/archon-grid/
Bold Signal自信、高冲击力路演PPT、主题演讲
Electric Studio简洁、专业代理机构演示文稿
Creative Voltage充满活力、复古现代创意路演
Dark Botanical优雅、精致高端品牌
Notebook Tabs编辑风格、有条理报告、评测
Pastel Geometry友好、平易近人产品概览
Split Pastel有趣、现代创意代理机构
Vintage Editorial诙谐、有个性个人品牌
Neon Cyber未来感、科技感科技初创公司
Terminal Green面向开发者开发工具、API
Swiss Modern极简、精准企业、数据类
Paper & Ink文学感、有思想叙事类

Step 2.0: Style Path Selection

步骤2.0:风格路径选择

First, ask how the user wants to choose their style:
Question: Style Selection Method
  • Header: "Style"
  • Question: "How would you like to choose your presentation style?"
  • Options:
    • "Show me options" — Generate 3 previews based on my needs (recommended for most users)
    • "I know what I want" — Let me pick from the preset list directly
If "Show me options" → Continue to Step 2.1 (Mood Selection)
If "I know what I want" → Show preset picker:
Question: Pick a Preset
  • Header: "Preset"
  • Question: "Which style would you like to use?"
  • Options:
    • "Archon" — Deep-tech cinematic + corporate brand assets (has ready-made template)
    • "Bold Signal" — Vibrant card on dark, confident and high-impact
    • "Dark Botanical" — Elegant dark with soft abstract shapes
If user picks Archon, ask a follow-up:
Question: Grid Animation
  • Header: "Animation"
  • Question: "Would you like animated grid glow lines in the background?"
  • Options:
    • "No grid (clean)" — Clean dark background, no grid pattern (recommended)
    • "With grid glow" — Subtle animated white grid lines that drift across the background
If "No grid" → use
templates/archon/
If "With grid glow" → use
templates/archon-grid/
(If user picks a non-Archon preset, skip to Phase 3. If they want to see more options, show additional presets or proceed to guided discovery.)
首先,询问用户想要如何选择风格:
问题:风格选择方式
  • 标题:“风格”
  • 问题:“你想要如何选择演示文稿的风格?”
  • 选项:
    • “给我展示选项” — 根据我的需求生成3个预览(推荐给大多数用户)
    • “我知道自己想要什么” — 让我直接从预设列表中选择
如果选择“给我展示选项” → 继续步骤2.1(氛围选择)
如果选择“我知道自己想要什么” → 展示预设选择器:
问题:选择预设
  • 标题:“预设”
  • 问题:“你想要使用哪种风格?”
  • 选项:
    • “Archon” — 深度科技电影感 + 企业品牌资产(有现成模板)
    • “Bold Signal” — 深色背景搭配活力卡片,自信且高冲击力
    • “Dark Botanical” — 优雅深色搭配柔和抽象形状
如果用户选择Archon,请追加问题:
问题:网格动画
  • 标题:“动画”
  • 问题:“你想要在背景中添加动画网格发光线条吗?”
  • 选项:
    • “无网格(简洁版)” — 干净的深色背景,无网格图案(推荐)
    • “带网格发光” — 微妙的白色动画网格线条在背景中漂移
如果选择“无网格” → 使用
templates/archon/
如果选择“带网格发光” → 使用
templates/archon-grid/
(如果用户选择非Archon预设,跳转到阶段3。如果他们想要查看更多选项,展示额外的预设或继续引导式探索。)

Step 2.1: Mood Selection (Guided Discovery)

步骤2.1:氛围选择(引导式探索)

Question 1: Feeling
  • Header: "Vibe"
  • Question: "What feeling should the audience have when viewing your slides?"
  • Options:
    • "Impressed/Confident" — Professional, trustworthy, this team knows what they're doing
    • "Excited/Energized" — Innovative, bold, this is the future
    • "Calm/Focused" — Clear, thoughtful, easy to follow
    • "Inspired/Moved" — Emotional, storytelling, memorable
  • multiSelect: true (can choose up to 2)
问题1:感受
  • 标题:“氛围”
  • 问题:“观众观看你的幻灯片时应该有什么感受?”
  • 选项:
    • “印象深刻/信任” — 专业、可靠,这个团队很懂行
    • “兴奋/充满活力” — 创新、大胆,这就是未来
    • “平静/专注” — 清晰、有思想,易于理解
    • “受启发/感动” — 有情感、叙事性强、令人难忘
  • 多选:是(最多可选2个)

Step 2.2: Generate Style Previews

步骤2.2:生成风格预览

Based on their mood selection, generate 3 distinct style previews as mini HTML files in a temporary directory. Each preview should be a single title slide showing:
  • Typography (font choices, heading/body hierarchy)
  • Color palette (background, accent, text colors)
  • Animation style (how elements enter)
  • Overall aesthetic feel
Preview Styles to Consider (pick 3 based on mood):
MoodStyle Options
Impressed/Confident"Bold Signal", "Electric Studio", "Dark Botanical"
Excited/Energized"Creative Voltage", "Neon Cyber", "Split Pastel"
Calm/Focused"Notebook Tabs", "Paper & Ink", "Swiss Modern"
Inspired/Moved"Dark Botanical", "Vintage Editorial", "Pastel Geometry"
IMPORTANT: Never use these generic patterns:
  • Purple gradients on white backgrounds
  • Inter, Roboto, or system fonts
  • Standard blue primary colors
  • Predictable hero layouts
Instead, use distinctive choices:
  • Unique font pairings (Clash Display, Satoshi, Cormorant Garamond, DM Sans, etc.)
  • Cohesive color themes with personality
  • Atmospheric backgrounds (gradients, subtle patterns, depth)
  • Signature animation moments
根据用户的氛围选择,在临时目录中生成3个不同的风格预览作为迷你HTML文件。每个预览应该是单个标题页,展示:
  • 排版(字体选择、标题/正文层级)
  • 调色板(背景、强调色、文字颜色)
  • 动画风格(元素入场方式)
  • 整体美学感受
可选择的预览风格(根据氛围选择3个):
氛围风格选项
印象深刻/信任"Bold Signal", "Electric Studio", "Dark Botanical"
兴奋/充满活力"Creative Voltage", "Neon Cyber", "Split Pastel"
平静/专注"Notebook Tabs", "Paper & Ink", "Swiss Modern"
受启发/感动"Dark Botanical", "Vintage Editorial", "Pastel Geometry"
重要提示:绝不要使用这些通用模式:
  • 白色背景搭配紫色渐变
  • Inter、Roboto或系统字体
  • 标准蓝色主色调
  • 可预测的 hero 布局
相反,请使用独特的选择:
  • 独特的字体组合(Clash Display、Satoshi、Cormorant Garamond、DM Sans等)
  • 有个性的统一配色主题
  • 氛围感背景(渐变、微妙图案、层次感)
  • 标志性的动画瞬间

Step 2.3: Present Previews

步骤2.3:展示预览

Create the previews in:
.claude-design/slide-previews/
.claude-design/slide-previews/
├── style-a.html   # First style option
├── style-b.html   # Second style option
├── style-c.html   # Third style option
└── assets/        # Any shared assets
Each preview file should be:
  • Self-contained (inline CSS/JS)
  • A single "title slide" showing the aesthetic
  • Animated to demonstrate motion style
  • ~50-100 lines, not a full presentation
Present to user:
I've created 3 style previews for you to compare:

**Style A: [Name]** — [1 sentence description]
**Style B: [Name]** — [1 sentence description]
**Style C: [Name]** — [1 sentence description]

Open each file to see them in action:
- .claude-design/slide-previews/style-a.html
- .claude-design/slide-previews/style-b.html
- .claude-design/slide-previews/style-c.html

Take a look and tell me:
1. Which style resonates most?
2. What do you like about it?
3. Anything you'd change?
Then use AskUserQuestion:
Question: Pick Your Style
  • Header: "Style"
  • Question: "Which style preview do you prefer?"
  • Options:
    • "Style A: [Name]" — [Brief description]
    • "Style B: [Name]" — [Brief description]
    • "Style C: [Name]" — [Brief description]
    • "Mix elements" — Combine aspects from different styles
If "Mix elements", ask for specifics.

.claude-design/slide-previews/
目录中创建预览:
.claude-design/slide-previews/
├── style-a.html   # 第一个风格选项
├── style-b.html   # 第二个风格选项
├── style-c.html   # 第三个风格选项
└── assets/        # 任何共享资源
每个预览文件应该:
  • 自包含(内联CSS/JS)
  • 单个“标题页”展示美学风格
  • 带有动画以展示运动风格
  • 约50-100行代码,不是完整的演示文稿
向用户展示:
我已经为你创建了3个风格预览供你比较:

**风格A: [名称]** — [1句话描述]
**风格B: [名称]** — [1句话描述]
**风格C: [名称]** — [1句话描述]

打开每个文件查看实际效果:
- .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:
问题:选择你的风格
  • 标题:“风格”
  • 问题:“你更喜欢哪个风格预览?”
  • 选项:
    • “风格A: [名称]” — [简短描述]
    • “风格B: [名称]” — [简短描述]
    • “风格C: [名称]” — [简短描述]
    • “混合元素” — 结合不同风格的特点
如果选择“混合元素”,请询问具体细节。

Phase 3: Generate Presentation

阶段3:生成演示文稿

Now generate the full presentation based on:
  • Content from Phase 1
  • Style from Phase 2
现在根据以下内容生成完整的演示文稿:
  • 阶段1的内容
  • 阶段2的风格

Using Templates (Preferred When Available)

使用模板(优先选择,如果有可用模板)

If the chosen style has a template (see preset table), copy the template as the starting point instead of building from scratch:
  1. Copy the template's
    template.html
    file to the target directory (rename to the presentation name)
  2. Copy the template's
    assets/
    folder alongside it — the HTML uses relative
    assets/
    paths
  3. Replace placeholder slide content with the user's actual content
  4. Add/remove slides as needed, following the template's existing patterns
Templates are located in:
~/.claude/skills/frontend-slides/templates/
Each template is a self-contained folder:
templates/<template-name>/
├── template.html        # The presentation HTML
└── assets/              # Images, logos, patterns used by the template
Currently available templates:
  • archon/
    — Deep-tech cinematic + corporate brand assets (Outfit + Inter fonts, animated grid glow, triangle mosaic, logo images)
如果选择的风格有模板(参见预设表格),复制模板作为起点而非从零开始构建:
  1. 将模板的
    template.html
    文件复制到目标目录(重命名为演示文稿名称)
  2. 将模板的
    assets/
    文件夹复制到旁边 — HTML使用相对的
    assets/
    路径
  3. 用用户的实际内容替换占位符幻灯片内容
  4. 根据需要添加/删除幻灯片,遵循模板的现有模式
模板位于:
~/.claude/skills/frontend-slides/templates/
每个模板都是一个独立的文件夹:
templates/<template-name>/
├── template.html        # 演示文稿HTML
└── assets/              # 模板使用的图片、标志、图案
当前可用的模板:
  • archon/
    — 深度科技电影感 + 企业品牌资产(Outfit + Inter字体、动画网格发光、三角形马赛克、标志图片)

File Structure

文件结构

For single presentations:
presentation.html    # Self-contained presentation
assets/              # Images, if any
For projects with multiple presentations:
[presentation-name].html
[presentation-name]-assets/
单个演示文稿的结构:
presentation.html    # 自包含的演示文稿
assets/              # 图片(如果有)
包含多个演示文稿的项目结构:
[presentation-name].html
[presentation-name]-assets/

HTML Architecture

HTML架构

Follow this structure for all presentations:
html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Presentation Title</title>

    <!-- Fonts (use Fontshare or Google Fonts) -->
    <link rel="stylesheet" href="https://api.fontshare.com/v2/css?f[]=...">

    <style>
        /* ===========================================
           CSS CUSTOM PROPERTIES (THEME)
           Easy to modify: change these to change the whole look
           =========================================== */
        :root {
            /* Colors */
            --bg-primary: #0a0f1c;
            --bg-secondary: #111827;
            --text-primary: #ffffff;
            --text-secondary: #9ca3af;
            --accent: #00ffcc;
            --accent-glow: rgba(0, 255, 204, 0.3);

            /* Typography - MUST use clamp() for responsive scaling */
            --font-display: 'Clash Display', sans-serif;
            --font-body: 'Satoshi', sans-serif;
            --title-size: clamp(2rem, 6vw, 5rem);
            --subtitle-size: clamp(0.875rem, 2vw, 1.25rem);
            --body-size: clamp(0.75rem, 1.2vw, 1rem);

            /* Spacing - MUST use clamp() for responsive scaling */
            --slide-padding: clamp(1.5rem, 4vw, 4rem);
            --content-gap: clamp(1rem, 2vw, 2rem);

            /* Animation */
            --ease-out-expo: cubic-bezier(0.16, 1, 0.3, 1);
            --duration-normal: 0.6s;
        }

        /* ===========================================
           BASE STYLES
           =========================================== */
        * {
            margin: 0;
            padding: 0;
            box-sizing: border-box;
        }

        html {
            scroll-behavior: smooth;
            scroll-snap-type: y mandatory;
            height: 100%;
        }

        body {
            font-family: var(--font-body);
            background: var(--bg-primary);
            color: var(--text-primary);
            overflow-x: hidden;
            height: 100%;
        }

        /* ===========================================
           SLIDE CONTAINER
           CRITICAL: Each slide MUST fit exactly in viewport
           - Use height: 100vh (NOT min-height)
           - Use overflow: hidden to prevent scroll
           - Content must scale with clamp() values
           =========================================== */
        .slide {
            width: 100vw;
            height: 100vh; /* EXACT viewport height - no scrolling */
            height: 100dvh; /* Dynamic viewport height for mobile */
            padding: var(--slide-padding);
            scroll-snap-align: start;
            display: flex;
            flex-direction: column;
            justify-content: center;
            position: relative;
            overflow: hidden; /* Prevent any content overflow */
        }

        /* Content wrapper that prevents overflow */
        .slide-content {
            flex: 1;
            display: flex;
            flex-direction: column;
            justify-content: center;
            max-height: 100%;
            overflow: hidden;
        }

        /* ===========================================
           RESPONSIVE BREAKPOINTS
           Adjust content for different screen sizes
           =========================================== */
        @media (max-height: 600px) {
            :root {
                --slide-padding: clamp(1rem, 3vw, 2rem);
                --content-gap: clamp(0.5rem, 1.5vw, 1rem);
            }
        }

        @media (max-width: 768px) {
            :root {
                --title-size: clamp(1.5rem, 8vw, 3rem);
            }
        }

        @media (max-height: 500px) and (orientation: landscape) {
            /* Extra compact for landscape phones */
            :root {
                --title-size: clamp(1.25rem, 5vw, 2rem);
                --slide-padding: clamp(0.75rem, 2vw, 1.5rem);
            }
        }

        /* ===========================================
           ANIMATIONS
           Trigger via .visible class (added by JS on scroll)
           =========================================== */
        .reveal {
            opacity: 0;
            transform: translateY(30px);
            transition: opacity var(--duration-normal) var(--ease-out-expo),
                        transform var(--duration-normal) var(--ease-out-expo);
        }

        .slide.visible .reveal {
            opacity: 1;
            transform: translateY(0);
        }

        /* Stagger children */
        .reveal:nth-child(1) { transition-delay: 0.1s; }
        .reveal:nth-child(2) { transition-delay: 0.2s; }
        .reveal:nth-child(3) { transition-delay: 0.3s; }
        .reveal:nth-child(4) { transition-delay: 0.4s; }

        /* ... more styles ... */
    </style>
</head>
<body>
    <!-- Progress bar (optional) -->
    <div class="progress-bar"></div>

    <!-- Navigation dots (optional) -->
    <nav class="nav-dots">
        <!-- Generated by JS -->
    </nav>

    <!-- Slides -->
    <section class="slide title-slide">
        <h1 class="reveal">Presentation Title</h1>
        <p class="reveal">Subtitle or author</p>
    </section>

    <section class="slide">
        <h2 class="reveal">Slide Title</h2>
        <p class="reveal">Content...</p>
    </section>

    <!-- More slides... -->

    <script>
        /* ===========================================
           SLIDE PRESENTATION CONTROLLER
           Handles navigation, animations, and interactions
           =========================================== */

        class SlidePresentation {
            constructor() {
                // ... initialization
            }

            // ... methods
        }

        // Initialize
        new SlidePresentation();
    </script>
</body>
</html>
所有演示文稿请遵循以下结构:
html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Presentation Title</title>

    <!-- Fonts (use Fontshare or Google Fonts) -->
    <link rel="stylesheet" href="https://api.fontshare.com/v2/css?f[]=...">

    <style>
        /* ===========================================
           CSS CUSTOM PROPERTIES (THEME)
           Easy to modify: change these to change the whole look
           =========================================== */
        :root {
            /* Colors */
            --bg-primary: #0a0f1c;
            --bg-secondary: #111827;
            --text-primary: #ffffff;
            --text-secondary: #9ca3af;
            --accent: #00ffcc;
            --accent-glow: rgba(0, 255, 204, 0.3);

            /* Typography - MUST use clamp() for responsive scaling */
            --font-display: 'Clash Display', sans-serif;
            --font-body: 'Satoshi', sans-serif;
            --title-size: clamp(2rem, 6vw, 5rem);
            --subtitle-size: clamp(0.875rem, 2vw, 1.25rem);
            --body-size: clamp(0.75rem, 1.2vw, 1rem);

            /* Spacing - MUST use clamp() for responsive scaling */
            --slide-padding: clamp(1.5rem, 4vw, 4rem);
            --content-gap: clamp(1rem, 2vw, 2rem);

            /* Animation */
            --ease-out-expo: cubic-bezier(0.16, 1, 0.3, 1);
            --duration-normal: 0.6s;
        }

        /* ===========================================
           BASE STYLES
           =========================================== */
        * {
            margin: 0;
            padding: 0;
            box-sizing: border-box;
        }

        html {
            scroll-behavior: smooth;
            scroll-snap-type: y mandatory;
            height: 100%;
        }

        body {
            font-family: var(--font-body);
            background: var(--bg-primary);
            color: var(--text-primary);
            overflow-x: hidden;
            height: 100%;
        }

        /* ===========================================
           SLIDE CONTAINER
           CRITICAL: Each slide MUST fit exactly in viewport
           - Use height: 100vh (NOT min-height)
           - Use overflow: hidden to prevent scroll
           - Content must scale with clamp() values
           =========================================== */
        .slide {
            width: 100vw;
            height: 100vh; /* EXACT viewport height - no scrolling */
            height: 100dvh; /* Dynamic viewport height for mobile */
            padding: var(--slide-padding);
            scroll-snap-align: start;
            display: flex;
            flex-direction: column;
            justify-content: center;
            position: relative;
            overflow: hidden; /* Prevent any content overflow */
        }

        /* Content wrapper that prevents overflow */
        .slide-content {
            flex: 1;
            display: flex;
            flex-direction: column;
            justify-content: center;
            max-height: 100%;
            overflow: hidden;
        }

        /* ===========================================
           RESPONSIVE BREAKPOINTS
           Adjust content for different screen sizes
           =========================================== */
        @media (max-height: 600px) {
            :root {
                --slide-padding: clamp(1rem, 3vw, 2rem);
                --content-gap: clamp(0.5rem, 1.5vw, 1rem);
            }
        }

        @media (max-width: 768px) {
            :root {
                --title-size: clamp(1.5rem, 8vw, 3rem);
            }
        }

        @media (max-height: 500px) and (orientation: landscape) {
            /* Extra compact for landscape phones */
            :root {
                --title-size: clamp(1.25rem, 5vw, 2rem);
                --slide-padding: clamp(0.75rem, 2vw, 1.5rem);
            }
        }

        /* ===========================================
           ANIMATIONS
           Trigger via .visible class (added by JS on scroll)
           =========================================== */
        .reveal {
            opacity: 0;
            transform: translateY(30px);
            transition: opacity var(--duration-normal) var(--ease-out-expo),
                        transform var(--duration-normal) var(--ease-out-expo);
        }

        .slide.visible .reveal {
            opacity: 1;
            transform: translateY(0);
        }

        /* Stagger children */
        .reveal:nth-child(1) { transition-delay: 0.1s; }
        .reveal:nth-child(2) { transition-delay: 0.2s; }
        .reveal:nth-child(3) { transition-delay: 0.3s; }
        .reveal:nth-child(4) { transition-delay: 0.4s; }

        /* ... more styles ... */
    </style>
</head>
<body>
    <!-- Progress bar (optional) -->
    <div class="progress-bar"></div>

    <!-- Navigation dots (optional) -->
    <nav class="nav-dots">
        <!-- Generated by JS -->
    </nav>

    <!-- Slides -->
    <section class="slide title-slide">
        <h1 class="reveal">Presentation Title</h1>
        <p class="reveal">Subtitle or author</p>
    </section>

    <section class="slide">
        <h2 class="reveal">Slide Title</h2>
        <p class="reveal">Content...</p>
    </section>

    <!-- More slides... -->

    <script>
        /* ===========================================
           SLIDE PRESENTATION CONTROLLER
           Handles navigation, animations, and interactions
           =========================================== */

        class SlidePresentation {
            constructor() {
                // ... initialization
            }

            // ... methods
        }

        // Initialize
        new SlidePresentation();
    </script>
</body>
</html>

Required JavaScript Features

必需的JavaScript功能

Every presentation should include:
  1. SlidePresentation Class — Main controller
    • Keyboard navigation (arrows, space)
    • Touch/swipe support
    • Mouse wheel navigation
    • Progress bar updates
    • Navigation dots
  2. Intersection Observer — For scroll-triggered animations
    • Add
      .visible
      class when slides enter viewport
    • Trigger CSS animations efficiently
  3. Optional Enhancements (based on style):
    • Custom cursor with trail
    • Particle system background (canvas)
    • Parallax effects
    • 3D tilt on hover
    • Magnetic buttons
    • Counter animations
每个演示文稿应包含:
  1. SlidePresentation类 — 主控制器
    • 键盘导航(方向键、空格键)
    • 触摸/滑动支持
    • 鼠标滚轮导航
    • 进度条更新
    • 导航点
  2. Intersection Observer — 用于滚动触发的动画
    • 当幻灯片进入视口时添加
      .visible
    • 高效触发CSS动画
  3. 可选增强功能(根据风格):
    • 带轨迹的自定义光标
    • 粒子系统背景(canvas)
    • 视差效果
    • 悬停时的3D倾斜效果
    • 磁吸按钮
    • 计数器动画

Code Quality Requirements

代码质量要求

Comments: Every section should have clear comments explaining:
  • What it does
  • Why it exists
  • How to modify it
javascript
/* ===========================================
   CUSTOM CURSOR
   Creates a stylized cursor that follows mouse with a trail effect.
   - Uses lerp (linear interpolation) for smooth movement
   - Grows larger when hovering over interactive elements
   =========================================== */
class CustomCursor {
    constructor() {
        // ...
    }
}
Accessibility:
  • Semantic HTML (
    <section>
    ,
    <nav>
    ,
    <main>
    )
  • Keyboard navigation works
  • ARIA labels where needed
  • Reduced motion support
css
@media (prefers-reduced-motion: reduce) {
    .reveal {
        transition: opacity 0.3s ease;
        transform: none;
    }
}
Responsive & Viewport Fitting (CRITICAL):
See the "CRITICAL: Viewport Fitting Requirements" section above for complete CSS and guidelines.
Quick reference:
  • Every
    .slide
    must have
    height: 100vh; height: 100dvh; overflow: hidden;
  • All typography and spacing must use
    clamp()
  • Respect content density limits (max 4-6 bullets, max 6 cards, etc.)
  • Include breakpoints for heights: 700px, 600px, 500px
  • When content doesn't fit → split into multiple slides, never scroll

注释: 每个部分都应有清晰的注释说明:
  • 它的作用
  • 存在的原因
  • 如何修改它
javascript
/* ===========================================
   CUSTOM CURSOR
   Creates a stylized cursor that follows mouse with a trail effect.
   - Uses lerp (linear interpolation) for smooth movement
   - Grows larger when hovering over interactive elements
   =========================================== */
class CustomCursor {
    constructor() {
        // ...
    }
}
可访问性:
  • 语义化HTML(
    <section>
    <nav>
    <main>
  • 键盘导航正常工作
  • 必要时使用ARIA标签
  • 支持减少动画的偏好设置
css
@media (prefers-reduced-motion: reduce) {
    .reveal {
        transition: opacity 0.3s ease;
        transform: none;
    }
}
响应式与视口适配(至关重要):
有关完整的CSS和指南,请参阅上方“至关重要:视口适配要求”部分。
快速参考:
  • 每个
    .slide
    必须设置
    height: 100vh; height: 100dvh; overflow: hidden;
  • 所有排版和间距必须使用
    clamp()
  • 遵守内容密度限制(最多4-6个项目符号,最多6个卡片等)
  • 针对以下高度设置断点:700px、600px、500px
  • 当内容无法适配时 → 拆分为多张幻灯片,绝不允许滚动

Phase 4: PPT Conversion

阶段4:PPT转换

When converting PowerPoint files:
转换PowerPoint文件时:

Step 4.1: Extract Content

步骤4.1:提取内容

Use Python with
python-pptx
to extract:
python
from pptx import Presentation
from pptx.util import Inches, Pt
import json
import os
import base64

def extract_pptx(file_path, output_dir):
    """
    Extract all content from a PowerPoint file.
    Returns a JSON structure with slides, text, and images.
    """
    prs = Presentation(file_path)
    slides_data = []

    # Create assets directory
    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:
            # Extract title
            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
                    })

            # Extract images
            if shape.shape_type == 13:  # Picture
                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
                })

        # Extract notes
        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
使用Python和
python-pptx
提取内容:
python
from pptx import Presentation
from pptx.util import Inches, Pt
import json
import os
import base64

def extract_pptx(file_path, output_dir):
    """
    Extract all content from a PowerPoint file.
    Returns a JSON structure with slides, text, and images.
    """
    prs = Presentation(file_path)
    slides_data = []

    # Create assets directory
    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:
            # Extract title
            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
                    })

            # Extract images
            if shape.shape_type == 13:  # Picture
                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
                })

        # Extract notes
        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

Step 4.2: Confirm Content Structure

步骤4.2:确认内容结构

Present the extracted content to the user:
I've extracted the following from your PowerPoint:

**Slide 1: [Title]**
- [Content summary]
- Images: [count]

**Slide 2: [Title]**
- [Content summary]
- Images: [count]

...

All images have been saved to the assets folder.

Does this look correct? Should I proceed with style selection?
向用户展示提取的内容:
我已经从你的PowerPoint中提取了以下内容:

**幻灯片1: [标题]**
- [内容摘要]
- 图片数量: [count]

**幻灯片2: [标题]**
- [内容摘要]
- 图片数量: [count]

...

所有图片已保存到assets文件夹。

内容看起来正确吗?我可以继续进行风格选择吗?

Step 4.3: Style Selection

步骤4.3:风格选择

Proceed to Phase 2 (Style Discovery) with the extracted content in mind.
结合提取的内容,进入阶段2(风格探索)。

Step 4.4: Generate HTML

步骤4.4:生成HTML

Convert the extracted content into the chosen style, preserving:
  • All text content
  • All images (referenced from assets folder)
  • Slide order
  • Any speaker notes (as HTML comments or separate file)

将提取的内容转换为选定的风格,保留:
  • 所有文字内容
  • 所有图片(从assets文件夹引用)
  • 幻灯片顺序
  • 任何演讲备注(作为HTML注释或单独文件)

Phase 5: Delivery

阶段5:交付

Final Output

最终输出

When the presentation is complete:
  1. Clean up temporary files
    • Delete
      .claude-design/slide-previews/
      if it exists
  2. Open the presentation
    • Use
      open [filename].html
      to launch in browser
  3. Provide summary
Your presentation is ready!

📁 File: [filename].html
🎨 Style: [Style Name]
📊 Slides: [count]

**Navigation:**
- Arrow keys (← →) or Space to navigate
- Scroll/swipe also works
- Click the dots on the right to jump to a slide

**To customize:**
- Colors: Look for `:root` CSS variables at the top
- Fonts: Change the Fontshare/Google Fonts link
- Animations: Modify `.reveal` class timings

Would you like me to make any adjustments?

演示文稿完成后:
  1. 清理临时文件
    • 如果存在,删除
      .claude-design/slide-previews/
  2. 打开演示文稿
    • 使用
      open [filename].html
      在浏览器中打开
  3. 提供摘要
你的演示文稿已准备好!

📁 文件: [filename].html
🎨 风格: [Style Name]
📊 幻灯片数量: [count]

**导航方式:**
- 方向键(← →)或空格键导航
- 滚动/滑动也可
- 点击右侧的点跳转到指定幻灯片

**自定义方法:**
- 颜色:查找顶部的`:root`CSS变量
- 字体:修改Fontshare/Google Fonts链接
- 动画:调整`.reveal`类的时间设置

你需要我做任何调整吗?

Deploying Presentations

部署演示文稿

When the presentation is complete (or the user asks to deploy/publish/share an existing one), offer the delivery choice:
Question: Delivery Method
  • Header: "Deliver"
  • Question: "How would you like to access the presentation?"
  • Options:
    • "Local only" — Just open it in my browser, no deploy
    • "Deploy to surge.sh" — Publish to a public URL for easy sharing
当演示文稿完成(或用户要求部署/发布/分享现有演示文稿)时,提供交付选项:
问题:交付方式
  • 标题:“交付”
  • 问题:“你想要如何访问演示文稿?”
  • 选项:
    • “仅本地” — 只在我的浏览器中打开,不部署
    • “部署到surge.sh” — 发布到公共URL以便分享

Local Only

仅本地

Open the file with
open [filename].html
and provide the summary from Phase 5. Done.
使用
open [filename].html
打开文件,并提供阶段5的摘要。完成。

Deploy to surge.sh

部署到surge.sh

Surge publishes a directory to
<name>.surge.sh
instantly. Requires the
surge
CLI (via
npx
) and a one-time
npx surge login
.
Deploy steps:
  1. Identify the presentation — which HTML file + its assets folder. Ask if unclear.
  2. Prepare deploy directory
    bash
    DEPLOY_DIR=$(mktemp -d)
    cp <presentation>.html "$DEPLOY_DIR/index.html"
    cp -r assets/ "$DEPLOY_DIR/assets/" 2>/dev/null || true
  3. Deploy
    bash
    npx surge "$DEPLOY_DIR" slides-<short-name>.surge.sh
    If surge asks for login, tell the user to run
    npx surge login
    in their terminal first, then retry.
  4. Return the URL
    https://slides-<short-name>.surge.sh
  5. Clean up
    rm -rf "$DEPLOY_DIR"
Surge可将目录即时发布到
<name>.surge.sh
。需要
surge
CLI(通过
npx
)和一次性的
npx surge login
部署步骤:
  1. 确定演示文稿 — 哪个HTML文件及其assets文件夹。如果不明确,请询问用户。
  2. 准备部署目录
    bash
    DEPLOY_DIR=$(mktemp -d)
    cp <presentation>.html "$DEPLOY_DIR/index.html"
    cp -r assets/ "$DEPLOY_DIR/assets/" 2>/dev/null || true
  3. 部署
    bash
    npx surge "$DEPLOY_DIR" slides-<short-name>.surge.sh
    如果surge要求登录,请告诉用户先在终端中运行
    npx surge login
    ,然后重试。
  4. 返回URL
    https://slides-<short-name>.surge.sh
  5. 清理
    rm -rf "$DEPLOY_DIR"

Re-deploying (updating an existing deployment)

重新部署(更新现有部署)

Run the same deploy steps again with the same domain — surge overwrites the previous version instantly.
再次运行相同的部署步骤并使用相同的域名 — surge会立即覆盖之前的版本。

Tearing down a deployment

拆除部署

bash
npx surge teardown slides-<short-name>.surge.sh

bash
npx surge teardown slides-<short-name>.surge.sh

Style Reference: Effect → Feeling Mapping

风格参考:效果→感受映射

Use this guide to match animations to intended feelings:
使用本指南将动画与预期感受匹配:

Dramatic / Cinematic

戏剧性 / 电影感

  • Slow fade-ins (1-1.5s)
  • Large scale transitions (0.9 → 1)
  • Dark backgrounds with spotlight effects
  • Parallax scrolling
  • Full-bleed images
  • 缓慢淡入(1-1.5秒)
  • 大尺度过渡(0.9 → 1)
  • 深色背景搭配聚光灯效果
  • 视差滚动
  • 全屏图片

Techy / Futuristic

科技感 / 未来感

  • Neon glow effects (box-shadow with accent color)
  • Particle systems (canvas background)
  • Grid patterns
  • Monospace fonts for accents
  • Glitch or scramble text effects
  • Cyan, magenta, electric blue palette
  • 霓虹发光效果(使用强调色的box-shadow)
  • 粒子系统(canvas背景)
  • 网格图案
  • 等宽字体用于强调
  • 故障或文字打乱效果
  • 青色、品红色、电光蓝调色板

Playful / Friendly

有趣 / 友好

  • Bouncy easing (spring physics)
  • Rounded corners (large radius)
  • Pastel or bright colors
  • Floating/bobbing animations
  • Hand-drawn or illustrated elements
  • 有弹性的缓动效果(弹簧物理)
  • 圆角(大半径)
  • 柔和或明亮的颜色
  • 漂浮/摆动动画
  • 手绘或插画元素

Professional / Corporate

专业 / 企业

  • Subtle, fast animations (200-300ms)
  • Clean sans-serif fonts
  • Navy, slate, or charcoal backgrounds
  • Precise spacing and alignment
  • Minimal decorative elements
  • Data visualization focus
  • 微妙、快速的动画(200-300毫秒)
  • 简洁的无衬线字体
  • 海军蓝、石板灰或炭灰色背景
  • 精准的间距和对齐
  • 极少的装饰元素
  • 专注于数据可视化

Calm / Minimal

平静 / 极简

  • Very slow, subtle motion
  • High whitespace
  • Muted color palette
  • Serif typography
  • Generous padding
  • Content-focused, no distractions
  • 非常缓慢、微妙的运动
  • 高留白
  • 柔和的调色板
  • 衬线字体
  • 充足的内边距
  • 以内容为中心,无干扰

Editorial / Magazine

编辑风格 / 杂志风

  • Strong typography hierarchy
  • Pull quotes and callouts
  • Image-text interplay
  • Grid-breaking layouts
  • Serif headlines, sans-serif body
  • Black and white with one accent

  • 强烈的排版层级
  • 拉引号和标注
  • 图文结合
  • 打破网格的布局
  • 衬线标题,无衬线正文
  • 黑白搭配一个强调色

Animation Patterns Reference

动画模式参考

Entrance Animations

入场动画

css
/* Fade + Slide Up (most common) */
.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);
}

/* Scale In */
.reveal-scale {
    opacity: 0;
    transform: scale(0.9);
    transition: opacity 0.6s, transform 0.6s var(--ease-out-expo);
}

/* Slide from Left */
.reveal-left {
    opacity: 0;
    transform: translateX(-50px);
    transition: opacity 0.6s, transform 0.6s var(--ease-out-expo);
}

/* Blur In */
.reveal-blur {
    opacity: 0;
    filter: blur(10px);
    transition: opacity 0.8s, filter 0.8s var(--ease-out-expo);
}
css
/* Fade + Slide Up (most common) */
.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);
}

/* Scale In */
.reveal-scale {
    opacity: 0;
    transform: scale(0.9);
    transition: opacity 0.6s, transform 0.6s var(--ease-out-expo);
}

/* Slide from Left */
.reveal-left {
    opacity: 0;
    transform: translateX(-50px);
    transition: opacity 0.6s, transform 0.6s var(--ease-out-expo);
}

/* Blur In */
.reveal-blur {
    opacity: 0;
    filter: blur(10px);
    transition: opacity 0.8s, filter 0.8s var(--ease-out-expo);
}

Background Effects

背景效果

css
/* Gradient Mesh */
.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 Texture */
.noise-bg {
    background-image: url("data:image/svg+xml,..."); /* Inline SVG noise */
}

/* Grid Pattern */
.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;
}
css
/* Gradient Mesh */
.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 Texture */
.noise-bg {
    background-image: url("data:image/svg+xml,..."); /* Inline SVG noise */
}

/* Grid Pattern */
.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;
}

Interactive Effects

交互效果

javascript
/* 3D Tilt on Hover */
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)';
        });
    }
}

javascript
/* 3D Tilt on Hover */
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)';
        });
    }
}

Troubleshooting

故障排除

Common Issues

常见问题

Fonts not loading:
  • Check Fontshare/Google Fonts URL
  • Ensure font names match in CSS
Animations not triggering:
  • Verify Intersection Observer is running
  • Check that
    .visible
    class is being added
Scroll snap not working:
  • Ensure
    scroll-snap-type
    on html/body
  • Each slide needs
    scroll-snap-align: start
Mobile issues:
  • Disable heavy effects at 768px breakpoint
  • Test touch events
  • Reduce particle count or disable canvas
Performance issues:
  • Use
    will-change
    sparingly
  • Prefer
    transform
    and
    opacity
    animations
  • Throttle scroll/mousemove handlers

字体未加载:
  • 检查Fontshare/Google Fonts URL
  • 确保CSS中的字体名称匹配
动画未触发:
  • 验证Intersection Observer是否在运行
  • 检查
    .visible
    类是否被添加
滚动吸附不工作:
  • 确保html/body上设置了
    scroll-snap-type
  • 每个幻灯片需要设置
    scroll-snap-align: start
移动端问题:
  • 在768px断点处禁用重型效果
  • 测试触摸事件
  • 减少粒子数量或禁用canvas
性能问题:
  • 谨慎使用
    will-change
  • 优先使用
    transform
    opacity
    动画
  • 节流scroll/mousemove事件处理程序

Related Skills

相关技能

  • learn — Generate FORZARA.md documentation for the presentation
  • frontend-design — For more complex interactive pages beyond slides
  • design-and-refine:design-lab — For iterating on component designs

  • learn — 为演示文稿生成FORZARA.md文档
  • frontend-design — 用于创建幻灯片之外的更复杂的交互页面
  • design-and-refine:design-lab — 用于迭代组件设计

Example Session Flow

示例会话流程

  1. User: "I want to create a pitch deck for my AI startup"
  2. Skill asks about purpose, length, content
  3. User shares their bullet points and key messages
  4. Skill asks about desired feeling (Impressed + Excited)
  5. Skill generates 3 style previews
  6. User picks Style B (Neon Cyber), asks for darker background
  7. Skill generates full presentation with all slides
  8. Skill opens the presentation in browser
  9. User requests tweaks to specific slides
  10. Final presentation delivered

  1. 用户:“我想为我的AI初创公司创建一个路演PPT”
  2. 技能询问用途、长度、内容
  3. 用户分享他们的项目符号和关键信息
  4. 技能询问期望感受(印象深刻 + 兴奋)
  5. 技能生成3个风格预览
  6. 用户选择风格B(Neon Cyber),要求背景更暗
  7. 技能生成包含所有幻灯片的完整演示文稿
  8. 技能在浏览器中打开演示文稿
  9. 用户请求调整特定幻灯片 10.deliver最终演示文稿

Conversion Session Flow

转换会话流程

  1. User: "Convert my slides.pptx to a web presentation"
  2. Skill extracts content and images from PPT
  3. Skill confirms extracted content with user
  4. Skill asks about desired feeling/style
  5. Skill generates style previews
  6. User picks a style
  7. Skill generates HTML presentation with preserved assets
  8. Final presentation delivered
  1. 用户:“把我的slides.pptx转换成网页演示文稿”
  2. 技能从PPT中提取内容和图片
  3. 技能与用户确认提取的内容
  4. 技能询问期望感受/风格
  5. 技能生成风格预览
  6. 用户选择一种风格
  7. 技能生成包含保留资源的HTML演示文稿
  8. deliver最终演示文稿