AI 演示设计原则与实践

幻灯片设计原则、视觉层级、数据可视化、叙事结构与受众适配


一、演示设计的第一性原理

演示文稿的本质不是"文档的图形化版本",而是一种时间轴上的叙事媒介。它和文档的核心区别在于:

  • 文档:读者控制节奏,可以跳读、回翻、搜索
  • 演示:演讲者控制节奏,观众线性接收,无法回翻

这个区别决定了演示设计的所有原则:每一页必须在 3-5 秒内被理解,信息密度必须远低于文档,视觉引导必须替代文字导航。

设计原则金字塔

               清 晰
              /    \
           简 洁    层 级
          /    \   /    \
       一 致   对 比   节 奏
      /    \   /    \   /    \
    对齐  留白 颜色 大小 重复 变化

从底向上:基础原则(对齐、留白)构成了简洁和层级,简洁和层级共同服务于最高目标——清晰。


二、视觉层级设计

2.1 信息优先级映射

每页幻灯片的信息可以分为三层,对应不同的视觉强度:

层级 内容 视觉处理 占页面比例
L1 核心信息 标题、关键结论 最大字号、主色调、最显眼位置 30-40%
L2 支撑信息 要点、数据 中等字号、次要色调 40-50%
L3 辅助信息 注释、来源、页码 小字号、浅色 10-20%

2.2 AI 实现视觉层级

// visual-hierarchy.ts

interface HierarchyConfig {
  l1: { fontSize: number; fontWeight: number; color: string; spacing: number };
  l2: { fontSize: number; fontWeight: number; color: string; spacing: number };
  l3: { fontSize: number; fontWeight: number; color: string; spacing: number };
}

function buildHierarchy(theme: Theme): HierarchyConfig {
  /**
   * Generate visual hierarchy from theme tokens.
   * Key ratios:
   * - L1:L2 font size ratio should be >= 1.5
   * - L2:L3 font size ratio should be >= 1.3
   * - Each level should have distinct weight or color
   */
  return {
    l1: {
      fontSize: theme.typography.sizeH1,
      fontWeight: theme.typography.weightHeading,
      color: theme.colors.textPrimary,
      spacing: theme.spacing.unit * theme.spacing.sectionGap,
    },
    l2: {
      fontSize: theme.typography.sizeBody,
      fontWeight: theme.typography.weightBody,
      color: theme.colors.textPrimary,
      spacing: theme.spacing.unit * theme.spacing.elementGap,
    },
    l3: {
      fontSize: theme.typography.sizeCaption,
      fontWeight: theme.typography.weightBody,
      color: theme.colors.textSecondary,
      spacing: theme.spacing.unit * 1,
    },
  };
}

function validateHierarchy(config: HierarchyConfig): string[] {
  const warnings: string[] = [];

  // Font size ratios
  const l1l2Ratio = config.l1.fontSize / config.l2.fontSize;
  if (l1l2Ratio < 1.5) {
    warnings.push(
      `L1:L2 font ratio is ${l1l2Ratio.toFixed(1)}, should be >= 1.5`
    );
  }

  const l2l3Ratio = config.l2.fontSize / config.l3.fontSize;
  if (l2l3Ratio < 1.3) {
    warnings.push(
      `L2:L3 font ratio is ${l2l3Ratio.toFixed(1)}, should be >= 1.3`
    );
  }

  // Contrast check
  const l1Contrast = calculateContrastRatio(config.l1.color, '#ffffff');
  if (l1Contrast < 4.5) {
    warnings.push(`L1 text contrast ${l1Contrast.toFixed(1)} < 4.5 (WCAG AA)`);
  }

  return warnings;
}

2.3 眯眼测试(Squint Test)

这是检验视觉层级最直观的方法:将幻灯片缩小到看不清文字,观察是否仍能分辨出信息的主次。

# squint_test.py
"""
Automated squint test: blur the slide image and check
if visual hierarchy is still distinguishable.
"""
import cv2
import numpy as np
from PIL import Image


def squint_test(slide_image_path: str) -> dict:
    """
    Simulate squint test by applying heavy Gaussian blur.
    Analyze if distinct visual regions remain identifiable.
    """
    img = cv2.imread(slide_image_path)
    gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

    # Heavy blur (simulates squinting)
    blurred = cv2.GaussianBlur(gray, (51, 51), 0)

    # Edge detection on blurred image
    edges = cv2.Canny(blurred, 30, 100)

    # Count distinct regions
    contours, _ = cv2.findContours(
        edges, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE
    )

    # Filter small contours (noise)
    significant_regions = [
        c for c in contours
        if cv2.contourArea(c) > (img.shape[0] * img.shape[1] * 0.01)
    ]

    # Analyze contrast distribution
    hist = cv2.calcHist([blurred], [0], None, [256], [0, 256])
    hist_normalized = hist / hist.sum()

    # Good hierarchy = bimodal or trimodal distribution
    peaks = find_peaks(hist_normalized.flatten())

    return {
        'distinct_regions': len(significant_regions),
        'contrast_peaks': len(peaks),
        'passes_squint_test': len(significant_regions) >= 2 and len(peaks) >= 2,
        'recommendation': (
            'Good visual hierarchy'
            if len(significant_regions) >= 2
            else 'Weak hierarchy - increase contrast between elements'
        ),
    }

三、数据可视化原则

3.1 图表类型选择矩阵

数据关系 推荐图表 避免 原因
比较(少量) 条形图 饼图 > 6 项 条形图长度比角度更易比较
比较(多量) 横向条形图 纵向条形图 标签可读性
趋势 折线图 面积图(多系列) 面积图系列重叠难以阅读
构成 堆叠条形 饼图(精确值) 饼图难以比较相近的切片
分布 直方图 / 箱线图 散点图(少量点) 散点需要足够数据量
关系 散点图 散点最适合展示两变量关系

3.2 图表生成集成

// chart-generator.ts

interface ChartConfig {
  type: 'bar' | 'line' | 'pie' | 'donut' | 'scatter' | 'horizontal-bar';
  data: ChartData;
  style: ChartStyle;
  dimensions: { width: number; height: number };
}

interface ChartData {
  labels: string[];
  datasets: {
    name: string;
    values: number[];
    color?: string;
  }[];
}

interface ChartStyle {
  colorPalette: string[];
  backgroundColor: string;
  gridColor: string;
  labelColor: string;
  fontSize: number;
  showLegend: boolean;
  showGrid: boolean;
}

function selectChartType(data: ChartData): string {
  /**
   * Auto-select the best chart type based on data characteristics.
   */
  const seriesCount = data.datasets.length;
  const categoryCount = data.labels.length;
  const hasNegatives = data.datasets.some(d => d.values.some(v => v < 0));

  // Single series percentage composition -> donut
  if (seriesCount === 1 && categoryCount <= 6) {
    const total = data.datasets[0].values.reduce((s, v) => s + v, 0);
    const allPositive = data.datasets[0].values.every(v => v > 0);
    if (allPositive && Math.abs(total - 100) < 5) {
      return 'donut';
    }
  }

  // Time series -> line
  if (categoryCount > 8 && !hasNegatives) {
    return 'line';
  }

  // Many categories -> horizontal bar
  if (categoryCount > 5) {
    return 'horizontal-bar';
  }

  return 'bar';
}

async function renderChart(config: ChartConfig): Promise<string> {
  /**
   * Render chart to PNG using server-side rendering.
   * Options: Chart.js with node-canvas, Vega-Lite, or Mermaid.
   */
  // Using QuickChart API for simplicity
  const quickChartConfig = {
    type: config.type === 'horizontal-bar' ? 'horizontalBar' : config.type,
    data: {
      labels: config.data.labels,
      datasets: config.data.datasets.map((ds, i) => ({
        label: ds.name,
        data: ds.values,
        backgroundColor: ds.color ?? config.style.colorPalette[i],
      })),
    },
    options: {
      plugins: {
        legend: { display: config.style.showLegend },
      },
      scales: config.type !== 'pie' && config.type !== 'donut'
        ? { y: { grid: { display: config.style.showGrid } } }
        : undefined,
    },
  };

  const url = `https://quickchart.io/chart?c=${encodeURIComponent(
    JSON.stringify(quickChartConfig)
  )}&w=${config.dimensions.width}&h=${config.dimensions.height}&bkg=${
    encodeURIComponent(config.style.backgroundColor)
  }`;

  return url;
}

3.3 数据可视化的黄金法则

  1. 数据墨水比最大化(Tufte):删除所有不传递数据的视觉元素
  2. 一图一结论:每张图表只传递一个核心信息,用标题点明结论而非描述数据
  3. 颜色有语义:绿色=增长/正面,红色=下降/负面,灰色=参照
  4. 标注关键值:不要让观众自己去读坐标轴,直接标注关键数据点
  5. 简化坐标轴:去掉不必要的刻度线,减少网格密度

四、叙事结构设计

4.1 经典叙事框架

      ┌─────────────┐
      │  情境建立     │  "现状是什么?"
      │  (Setup)     │  1-2 页
      └──────┬───────┘
             │
      ┌──────v───────┐
      │  冲突/问题    │  "为什么这很重要?"
      │  (Conflict)  │  1-2 页
      └──────┬───────┘
             │
      ┌──────v───────┐
      │  解决方案     │  "我们怎么做?"
      │  (Solution)  │  3-5 页(核心内容)
      └──────┬───────┘
             │
      ┌──────v───────┐
      │  证据/数据    │  "为什么可行?"
      │  (Evidence)  │  2-3 页
      └──────┬───────┘
             │
      ┌──────v───────┐
      │  行动号召     │  "下一步是什么?"
      │  (CTA)       │  1 页
      └─────────────┘

4.2 叙事结构的 AI 实现

// narrative-planner.ts

type NarrativeArc =
  | 'problem-solution'    // 最常见:问题 -> 解决方案
  | 'journey'             // 旅程:现状 -> 过程 -> 结果
  | 'compare-contrast'    // 对比:A vs B -> 选择
  | 'data-story'          // 数据叙事:趋势 -> 洞察 -> 行动
  | 'tutorial';           // 教学:概念 -> 步骤 -> 实践

interface NarrativePlan {
  arc: NarrativeArc;
  acts: NarrativeAct[];
  totalPages: number;
}

interface NarrativeAct {
  name: string;
  purpose: string;
  pageCount: number;
  slideTypes: string[];
  emotionalTone: 'neutral' | 'tension' | 'resolution' | 'excitement';
}

async function planNarrative(
  content: ParsedContent,
  audience: string,
  goal: string,
): Promise<NarrativePlan> {
  const prompt = `Plan the narrative structure for a presentation.

Content themes: ${content.keyThemes.join(', ')}
Audience: ${audience}
Goal: ${goal}
Available pages: ${content.suggestedPageCount}

Choose the best narrative arc and plan the acts.
Output as JSON:
{
  "arc": "problem-solution",
  "acts": [
    {
      "name": "Setup",
      "purpose": "Establish the current situation",
      "pageCount": 2,
      "slideTypes": ["cover", "context"],
      "emotionalTone": "neutral"
    }
  ],
  "totalPages": 10
}`;

  const response = await llm.chat({
    model: 'gemini-2.5-flash',
    messages: [{ role: 'user', content: prompt }],
    responseFormat: { type: 'json_object' },
  });

  return JSON.parse(response.content);
}

4.3 开场设计模式

好的开场决定了观众是否会继续关注。以下是经过验证的开场模式:

模式 适用场景 示例
惊人数据 数据驱动的演讲 "每天有 X 万条数据被浪费"
提问 思辨性话题 "如果 AI 能做到 X,会发生什么?"
故事 产品/案例演讲 "上周,一个客户遇到了..."
对比 变革/趋势 "2020 年... vs 2025 年..."
痛点 解决方案类 "你是否经常遇到 X 问题?"

五、受众适配策略

5.1 受众分析维度

// audience-adapter.ts

interface AudienceProfile {
  type: 'executive' | 'technical' | 'general' | 'academic' | 'sales';
  expertise: 'novice' | 'intermediate' | 'expert';
  decisionMaker: boolean;
  timeConstraint: 'short' | 'standard' | 'extended'; // 5min / 15min / 30min+
}

interface AdaptationRules {
  maxBulletsPerPage: number;
  preferChart: boolean;
  technicalDepth: 'high' | 'medium' | 'low';
  jargonLevel: 'none' | 'moderate' | 'heavy';
  emphasisOn: 'impact' | 'method' | 'cost' | 'timeline';
  ctaStyle: 'direct' | 'suggestive' | 'data-backed';
}

function getAdaptationRules(profile: AudienceProfile): AdaptationRules {
  switch (profile.type) {
    case 'executive':
      return {
        maxBulletsPerPage: 3,
        preferChart: true,
        technicalDepth: 'low',
        jargonLevel: 'none',
        emphasisOn: 'impact',
        ctaStyle: 'direct',
      };
    case 'technical':
      return {
        maxBulletsPerPage: 5,
        preferChart: true,
        technicalDepth: 'high',
        jargonLevel: 'heavy',
        emphasisOn: 'method',
        ctaStyle: 'data-backed',
      };
    case 'sales':
      return {
        maxBulletsPerPage: 3,
        preferChart: true,
        technicalDepth: 'low',
        jargonLevel: 'none',
        emphasisOn: 'cost',
        ctaStyle: 'direct',
      };
    case 'academic':
      return {
        maxBulletsPerPage: 5,
        preferChart: true,
        technicalDepth: 'high',
        jargonLevel: 'moderate',
        emphasisOn: 'method',
        ctaStyle: 'suggestive',
      };
    default:
      return {
        maxBulletsPerPage: 4,
        preferChart: false,
        technicalDepth: 'medium',
        jargonLevel: 'none',
        emphasisOn: 'impact',
        ctaStyle: 'suggestive',
      };
  }
}

5.2 内容密度适配

function adaptContentDensity(
  slides: SlidePlan[],
  rules: AdaptationRules,
): SlidePlan[] {
  return slides.map(slide => {
    if (!slide.content.bullets) return slide;

    let bullets = slide.content.bullets;

    // Enforce max bullets per page
    if (bullets.length > rules.maxBulletsPerPage) {
      // Strategy: keep the most important ones
      bullets = bullets.slice(0, rules.maxBulletsPerPage);
    }

    // Adjust bullet length based on audience
    if (rules.technicalDepth === 'low') {
      bullets = bullets.map(b =>
        b.length > 60 ? b.slice(0, 57) + '...' : b
      );
    }

    return {
      ...slide,
      content: { ...slide.content, bullets },
    };
  });
}

六、幻灯片设计的十大原则

原则清单

编号 原则 核心要义 AI 实现方式
1 一页一信息 每页只传递一个核心观点 内容解析时强制拆分
2 标题即结论 标题不是描述,是判断 LLM 优化标题
3 文字最少化 能用图就不用文字 自动图表替代
4 6x6 规则 最多 6 行,每行最多 6 词 强制截断
5 留白是设计 留白 >= 40% 布局约束
6 一致性 字体/颜色/间距统一 模板系统
7 对比制造焦点 用大小/颜色/位置引导视线 视觉层级算法
8 数据说话 数据用图表,不用文字 自动图表选型
9 动画克制 动画服务于叙事,不服务于装饰 默认无动画
10 结尾有力 最后一页是行动号召,不是"谢谢" 叙事框架

用 AI 实现的实战建议

// design-principles-validator.ts

interface ValidationResult {
  principle: string;
  status: 'pass' | 'warn' | 'fail';
  message: string;
}

function validateDesignPrinciples(
  slides: ResolvedSlide[],
): ValidationResult[] {
  const results: ValidationResult[] = [];

  for (const slide of slides) {
    // Principle 1: One message per slide
    const textElements = slide.elements.filter(
      e => e.role === 'body' || e.role === 'title'
    );
    const totalWords = textElements.reduce(
      (sum, e) => sum + String(e.content).split(/\s+/).length,
      0
    );
    if (totalWords > 60) {
      results.push({
        principle: 'one-message',
        status: 'warn',
        message: `Slide ${slide.index}: ${totalWords} words (recommend < 60)`,
      });
    }

    // Principle 5: Whitespace >= 40%
    const coveredArea = slide.elements.reduce(
      (sum, e) => sum + (e.width * e.height),
      0
    );
    const totalArea = slide.width * slide.height;
    const whitespace = 1 - (coveredArea / totalArea);
    if (whitespace < 0.4) {
      results.push({
        principle: 'whitespace',
        status: 'warn',
        message: `Slide ${slide.index}: ${(whitespace * 100).toFixed(0)}% whitespace (recommend >= 40%)`,
      });
    }

    // Principle 4: 6x6 rule
    const bodyElement = slide.elements.find(e => e.role === 'body');
    if (bodyElement) {
      const lines = String(bodyElement.content).split('\n');
      if (lines.length > 6) {
        results.push({
          principle: '6x6-rule',
          status: 'fail',
          message: `Slide ${slide.index}: ${lines.length} lines (max 6)`,
        });
      }
    }
  }

  return results;
}

七、从原则到实践的完整路径

1. 明确受众和目标
   |
   v
2. 选择叙事框架 (problem-solution / journey / data-story)
   |
   v
3. 规划信息架构 (一页一信息)
   |
   v
4. 应用模板 (保证视觉一致性)
   |
   v
5. 建立视觉层级 (L1/L2/L3)
   |
   v
6. 数据可视化 (图表 > 文字)
   |
   v
7. 设计验证 (眯眼测试 + 原则校验)
   |
   v
8. 受众适配 (内容密度 + 术语深度)
   |
   v
9. 最终审核 (一致性 + 叙事流畅度)

演示设计不是让幻灯片"好看",而是让观众在最短时间内理解最重要的信息,并采取你期望的行动。所有设计决策都应该服务于这个目标。


Maurice | maurice_wen@proton.me