PPT模板工程:设计系统与自动化

引言

PPT 模板不只是"一套好看的母版"——它是一套设计系统的物化表达。好的模板工程能让 100 个人做出风格一致的演示文稿,差的模板工程则让每份 PPT 都变成"各自为战"。本文从设计系统理论出发,深入模板的工程化构建、程序化生成和自动化管理。

一、设计系统与模板的关系

1.1 三层架构

┌───────────────────────────────────────────────┐
│              设计系统(Design System)           │
│  原子:颜色/字体/间距/圆角/阴影                   │
│  分子:按钮/标签/数据卡片/图标+文字               │
│  组织:标题区/内容区/图表区/脚注区                 │
├───────────────────────────────────────────────┤
│              模板层(Template Layer)            │
│  布局模板:标题页/内容页/双栏/全图/结尾页          │
│  变体:浅色/深色/品牌A/品牌B                      │
│  占位符:文本框/图片框/图表框/表格框               │
├───────────────────────────────────────────────┤
│              实例层(Instance Layer)            │
│  具体演示文稿:填入真实内容的最终产物               │
└───────────────────────────────────────────────┘

1.2 设计令牌(Design Tokens)

设计令牌是设计系统与模板之间的"合同"——它把视觉决策从具体实现中抽离出来:

{
  "brand": {
    "name": "灵阙科技",
    "slogan": "AI Empowered Enterprise"
  },
  "color": {
    "primary": "#1A56DB",
    "primary_light": "#3B82F6",
    "primary_dark": "#1E40AF",
    "secondary": "#6B7280",
    "accent": "#F59E0B",
    "success": "#059669",
    "warning": "#D97706",
    "error": "#DC2626",
    "bg_light": "#FFFFFF",
    "bg_dark": "#0F172A",
    "bg_section": "#F1F5F9",
    "text_heading": "#1F2937",
    "text_body": "#374151",
    "text_muted": "#9CA3AF",
    "text_inverse": "#F8FAFC"
  },
  "typography": {
    "heading_family": "Microsoft YaHei",
    "body_family": "Microsoft YaHei",
    "mono_family": "JetBrains Mono",
    "h1_size": 44,
    "h2_size": 32,
    "h3_size": 24,
    "body_size": 18,
    "body_small": 14,
    "caption_size": 12,
    "heading_weight": "bold",
    "body_weight": "regular",
    "line_height": 1.5
  },
  "spacing": {
    "page_margin_top": 50,
    "page_margin_bottom": 50,
    "page_margin_left": 60,
    "page_margin_right": 60,
    "section_gap": 32,
    "element_gap": 16,
    "small_gap": 8
  },
  "shape": {
    "corner_radius": 8,
    "border_width": 0,
    "shadow": "none"
  },
  "slide": {
    "width": 13.333,
    "height": 7.5,
    "aspect_ratio": "16:9"
  }
}

二、布局系统设计

2.1 网格系统

16:9 幻灯片网格(12 列 + 8 行)

  ┌─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┐
  │ │ │ │ │ │ │ │ │ │ │ │ │  ← 页眉区(Logo + 页码)
  ├─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┤
  │ │ │ │ │ │ │ │ │ │ │ │ │
  │ │ │ │ │ │ │ │ │ │ │ │ │  ← 标题区(2 行高)
  ├─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┤
  │ │ │ │ │ │ │ │ │ │ │ │ │
  │ │ │ │ │ │ │ │ │ │ │ │ │
  │ │ │ │ │ │ │ │ │ │ │ │ │  ← 内容区(4 行高)
  │ │ │ │ │ │ │ │ │ │ │ │ │
  ├─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┤
  │ │ │ │ │ │ │ │ │ │ │ │ │  ← 页脚区(来源 + 版权)
  └─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┘

列宽 = (页面宽度 - 左右边距) / 12
行高 = (页面高度 - 上下边距) / 8
列间距(Gutter)= 16pt

2.2 核心布局模板

Layout 1: 标题页(Title Slide)
┌──────────────────────────────────┐
│              [Logo]              │
│                                  │
│         大标题(H1)              │
│         副标题(Body)            │
│                                  │
│     作者 | 日期 | 部门            │
└──────────────────────────────────┘

Layout 2: 内容页(Content Slide)
┌──────────────────────────────────┐
│ [Logo]              [页码]       │
│ 标题(H2)                       │
│ ────────────────────             │
│ - 要点一                         │
│ - 要点二                         │
│ - 要点三                         │
│                    [来源]        │
└──────────────────────────────────┘

Layout 3: 双栏(Two Column)
┌──────────────────────────────────┐
│ [Logo]              [页码]       │
│ 标题(H2)                       │
│ ────────────────────             │
│ 左栏内容     │  右栏内容         │
│              │                   │
│              │                   │
│                    [来源]        │
└──────────────────────────────────┘

Layout 4: 大数字(Big Number)
┌──────────────────────────────────┐
│ [Logo]              [页码]       │
│                                  │
│           $12.5M                 │
│          +32% YoY                │
│    Q3 营收创下历史新高             │
│                                  │
└──────────────────────────────────┘

Layout 5: 全图(Full Image)
┌──────────────────────────────────┐
│░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░│
│░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░│
│░░░░░ 标题(白字叠加) ░░░░░░░░░░│
│░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░│
│░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░│
└──────────────────────────────────┘

Layout 6: 对比页(Comparison)
┌──────────────────────────────────┐
│ [Logo]              [页码]       │
│ 标题(H2)                       │
│ ────────────────────             │
│   方案 A      vs      方案 B     │
│   - 优点 1            - 优点 1   │
│   - 优点 2            - 优点 2   │
│   - 缺点 1            - 缺点 1   │
└──────────────────────────────────┘

Layout 7: 时间线(Timeline)
┌──────────────────────────────────┐
│ [Logo]              [页码]       │
│ 标题(H2)                       │
│ ────────────────────             │
│  Q1 ──── Q2 ──── Q3 ──── Q4     │
│  里程碑1  里程碑2  里程碑3  目标   │
│                                  │
└──────────────────────────────────┘

Layout 8: 结尾页(Closing Slide)
┌──────────────────────────────────┐
│                                  │
│          谢谢                    │
│          Thank You               │
│                                  │
│     联系方式 | 网站 | 二维码      │
│              [Logo]              │
└──────────────────────────────────┘

三、程序化模板构建

3.1 模板生成器

from pptx import Presentation
from pptx.util import Inches, Pt, Emu
from pptx.dml.color import RGBColor
from pptx.enum.text import PP_ALIGN, MSO_ANCHOR
import json

class TemplateBuilder:
    """PPT 模板程序化构建器"""

    def __init__(self, tokens_path: str):
        with open(tokens_path) as f:
            self.tokens = json.load(f)
        self.prs = Presentation()
        self._set_slide_size()

    def _set_slide_size(self):
        """设置幻灯片尺寸(16:9)"""
        self.prs.slide_width = Inches(self.tokens["slide"]["width"])
        self.prs.slide_height = Inches(self.tokens["slide"]["height"])

    def _hex_to_rgb(self, hex_color: str) -> RGBColor:
        hex_color = hex_color.lstrip("#")
        return RGBColor(
            int(hex_color[0:2], 16),
            int(hex_color[2:4], 16),
            int(hex_color[4:6], 16)
        )

    def build_title_slide(self) -> None:
        """构建标题页布局"""
        layout = self.prs.slide_layouts[6]  # Blank layout
        slide = self.prs.slides.add_slide(layout)

        # 背景色
        bg = slide.background
        fill = bg.fill
        fill.solid()
        fill.fore_color.rgb = self._hex_to_rgb(self.tokens["color"]["primary"])

        # 主标题
        title_box = slide.shapes.add_textbox(
            Inches(1.5), Inches(2.0),
            Inches(10.3), Inches(1.5)
        )
        tf = title_box.text_frame
        tf.word_wrap = True
        p = tf.paragraphs[0]
        p.text = "演示标题"
        p.font.size = Pt(self.tokens["typography"]["h1_size"])
        p.font.color.rgb = self._hex_to_rgb(self.tokens["color"]["text_inverse"])
        p.font.bold = True
        p.font.name = self.tokens["typography"]["heading_family"]
        p.alignment = PP_ALIGN.CENTER

        # 副标题
        sub_box = slide.shapes.add_textbox(
            Inches(2.5), Inches(3.8),
            Inches(8.3), Inches(0.8)
        )
        tf = sub_box.text_frame
        p = tf.paragraphs[0]
        p.text = "副标题 | 作者 | 日期"
        p.font.size = Pt(self.tokens["typography"]["body_size"])
        p.font.color.rgb = self._hex_to_rgb(self.tokens["color"]["text_inverse"])
        p.font.name = self.tokens["typography"]["body_family"]
        p.alignment = PP_ALIGN.CENTER

    def build_content_slide(self) -> None:
        """构建内容页布局"""
        layout = self.prs.slide_layouts[6]
        slide = self.prs.slides.add_slide(layout)

        # 标题
        title_box = slide.shapes.add_textbox(
            Inches(0.8), Inches(0.5),
            Inches(11.7), Inches(0.8)
        )
        tf = title_box.text_frame
        p = tf.paragraphs[0]
        p.text = "页面标题"
        p.font.size = Pt(self.tokens["typography"]["h2_size"])
        p.font.color.rgb = self._hex_to_rgb(self.tokens["color"]["text_heading"])
        p.font.bold = True
        p.font.name = self.tokens["typography"]["heading_family"]

        # 分隔线
        line = slide.shapes.add_connector(
            1,  # MSO_CONNECTOR_TYPE.STRAIGHT
            Inches(0.8), Inches(1.4),
            Inches(12.5), Inches(1.4)
        )
        line.line.color.rgb = self._hex_to_rgb(self.tokens["color"]["primary"])
        line.line.width = Pt(2)

        # 内容区占位
        content_box = slide.shapes.add_textbox(
            Inches(0.8), Inches(1.7),
            Inches(11.7), Inches(4.8)
        )
        tf = content_box.text_frame
        tf.word_wrap = True
        for i in range(3):
            if i > 0:
                p = tf.add_paragraph()
            else:
                p = tf.paragraphs[0]
            p.text = f"要点 {i + 1}"
            p.font.size = Pt(self.tokens["typography"]["body_size"])
            p.font.color.rgb = self._hex_to_rgb(self.tokens["color"]["text_body"])
            p.font.name = self.tokens["typography"]["body_family"]
            p.space_after = Pt(12)

        # 页码
        page_box = slide.shapes.add_textbox(
            Inches(12.0), Inches(6.8),
            Inches(1.0), Inches(0.4)
        )
        tf = page_box.text_frame
        p = tf.paragraphs[0]
        p.text = "2"
        p.font.size = Pt(self.tokens["typography"]["caption_size"])
        p.font.color.rgb = self._hex_to_rgb(self.tokens["color"]["text_muted"])
        p.alignment = PP_ALIGN.RIGHT

    def build_two_column_slide(self) -> None:
        """构建双栏布局"""
        layout = self.prs.slide_layouts[6]
        slide = self.prs.slides.add_slide(layout)

        # 标题
        title_box = slide.shapes.add_textbox(
            Inches(0.8), Inches(0.5),
            Inches(11.7), Inches(0.8)
        )
        tf = title_box.text_frame
        p = tf.paragraphs[0]
        p.text = "双栏标题"
        p.font.size = Pt(self.tokens["typography"]["h2_size"])
        p.font.bold = True
        p.font.name = self.tokens["typography"]["heading_family"]

        # 左栏
        left_box = slide.shapes.add_textbox(
            Inches(0.8), Inches(1.7),
            Inches(5.5), Inches(4.8)
        )
        tf = left_box.text_frame
        tf.word_wrap = True
        p = tf.paragraphs[0]
        p.text = "左栏内容"
        p.font.size = Pt(self.tokens["typography"]["body_size"])

        # 右栏
        right_box = slide.shapes.add_textbox(
            Inches(6.8), Inches(1.7),
            Inches(5.7), Inches(4.8)
        )
        tf = right_box.text_frame
        tf.word_wrap = True
        p = tf.paragraphs[0]
        p.text = "右栏内容"
        p.font.size = Pt(self.tokens["typography"]["body_size"])

    def build_big_number_slide(self) -> None:
        """构建大数字布局"""
        layout = self.prs.slide_layouts[6]
        slide = self.prs.slides.add_slide(layout)

        # 大数字
        num_box = slide.shapes.add_textbox(
            Inches(1.0), Inches(1.5),
            Inches(11.3), Inches(2.5)
        )
        tf = num_box.text_frame
        tf.word_wrap = True
        p = tf.paragraphs[0]
        p.text = "$12.5M"
        p.font.size = Pt(72)
        p.font.color.rgb = self._hex_to_rgb(self.tokens["color"]["primary"])
        p.font.bold = True
        p.alignment = PP_ALIGN.CENTER

        # 变化指标
        delta_box = slide.shapes.add_textbox(
            Inches(1.0), Inches(3.8),
            Inches(11.3), Inches(0.8)
        )
        tf = delta_box.text_frame
        p = tf.paragraphs[0]
        p.text = "+32% vs Q2"
        p.font.size = Pt(28)
        p.font.color.rgb = self._hex_to_rgb(self.tokens["color"]["success"])
        p.alignment = PP_ALIGN.CENTER

        # 说明
        desc_box = slide.shapes.add_textbox(
            Inches(1.0), Inches(4.8),
            Inches(11.3), Inches(0.6)
        )
        tf = desc_box.text_frame
        p = tf.paragraphs[0]
        p.text = "Q3 营收创下历史新高"
        p.font.size = Pt(self.tokens["typography"]["body_size"])
        p.font.color.rgb = self._hex_to_rgb(self.tokens["color"]["text_muted"])
        p.alignment = PP_ALIGN.CENTER

    def save(self, output_path: str):
        self.prs.save(output_path)

3.2 模板变体生成

class TemplateVariantGenerator:
    """模板变体生成器"""

    THEMES = {
        "light": {
            "bg": "#FFFFFF",
            "text_heading": "#1F2937",
            "text_body": "#374151",
            "accent": "#1A56DB"
        },
        "dark": {
            "bg": "#0F172A",
            "text_heading": "#F8FAFC",
            "text_body": "#E2E8F0",
            "accent": "#38BDF8"
        },
        "warm": {
            "bg": "#FFFBEB",
            "text_heading": "#78350F",
            "text_body": "#92400E",
            "accent": "#D97706"
        },
        "cool": {
            "bg": "#F0F9FF",
            "text_heading": "#0C4A6E",
            "text_body": "#075985",
            "accent": "#0284C7"
        }
    }

    def generate_variants(self, base_tokens: dict,
                           themes: list[str] = None) -> dict:
        """生成多个主题变体的 tokens"""
        themes = themes or list(self.THEMES.keys())
        variants = {}

        for theme_name in themes:
            theme = self.THEMES[theme_name]
            variant = json.loads(json.dumps(base_tokens))

            variant["color"]["bg_light"] = theme["bg"]
            variant["color"]["text_heading"] = theme["text_heading"]
            variant["color"]["text_body"] = theme["text_body"]
            variant["color"]["primary"] = theme["accent"]

            variants[theme_name] = variant

        return variants

四、模板管理系统

4.1 模板仓库结构

templates/
  registry.json              # 模板注册表(元数据)
  tokens/
    default.json             # 默认设计令牌
    brand-a.json             # 品牌 A 令牌
    brand-b.json             # 品牌 B 令牌
  layouts/
    title.py                 # 标题页构建器
    content.py               # 内容页构建器
    two-column.py            # 双栏构建器
    big-number.py            # 大数字构建器
    comparison.py            # 对比页构建器
    timeline.py              # 时间线构建器
    closing.py               # 结尾页构建器
  presets/
    sales-proposal/          # 销售提案预设
      config.json            # 页面顺序 + 布局选择
      content-hints.json     # AI 生成提示
    quarterly-report/        # 季度汇报预设
      config.json
      content-hints.json
    training-deck/           # 培训教材预设
      config.json
      content-hints.json
  assets/
    logos/
    icons/
    backgrounds/

4.2 模板注册表

{
  "version": "2.0",
  "templates": [
    {
      "id": "sales-proposal-v2",
      "name": "销售提案",
      "category": "sales",
      "tokens": "tokens/brand-a.json",
      "layouts": ["title", "content", "two-column", "big-number", "comparison", "closing"],
      "preset": "presets/sales-proposal/config.json",
      "thumbnail": "assets/thumbnails/sales-proposal.png",
      "tags": ["销售", "提案", "客户"],
      "usage_count": 342,
      "avg_rating": 4.5,
      "status": "published"
    },
    {
      "id": "quarterly-report-v1",
      "name": "季度汇报",
      "category": "report",
      "tokens": "tokens/default.json",
      "layouts": ["title", "content", "big-number", "two-column", "timeline", "closing"],
      "preset": "presets/quarterly-report/config.json",
      "thumbnail": "assets/thumbnails/quarterly-report.png",
      "tags": ["汇报", "季度", "数据"],
      "usage_count": 218,
      "avg_rating": 4.3,
      "status": "published"
    }
  ]
}

4.3 预设配置

{
  "id": "sales-proposal-v2",
  "slide_sequence": [
    {
      "layout": "title",
      "purpose": "开场:公司 + 方案名称",
      "variables": ["company_name", "proposal_title", "date", "author"]
    },
    {
      "layout": "content",
      "purpose": "客户痛点分析",
      "content_hint": "列出 3-5 个客户当前面临的核心痛点",
      "variables": ["pain_points"]
    },
    {
      "layout": "big-number",
      "purpose": "市场机会/关键数据",
      "content_hint": "展示一个能震撼客户的市场数据",
      "variables": ["big_number", "delta", "description"]
    },
    {
      "layout": "two-column",
      "purpose": "方案概述",
      "content_hint": "左栏:方案架构图/流程;右栏:关键特性列表",
      "variables": ["solution_overview", "key_features"]
    },
    {
      "layout": "comparison",
      "purpose": "竞品对比",
      "content_hint": "我们 vs 竞品的核心差异",
      "variables": ["our_advantages", "competitor_comparison"]
    },
    {
      "layout": "content",
      "purpose": "实施计划与时间线",
      "content_hint": "分阶段实施计划,含里程碑和交付物",
      "variables": ["implementation_plan"]
    },
    {
      "layout": "big-number",
      "purpose": "投资回报",
      "content_hint": "ROI 或成本节省的关键数字",
      "variables": ["roi_number", "roi_delta", "roi_description"]
    },
    {
      "layout": "closing",
      "purpose": "结尾:联系方式",
      "variables": ["contact_name", "contact_email", "contact_phone"]
    }
  ]
}

五、AI 驱动的模板生成

5.1 从需求到 PPT

class AITemplateEngine:
    """AI 驱动的模板引擎"""

    def __init__(self, llm_client, template_registry: dict):
        self.llm = llm_client
        self.registry = template_registry

    async def generate_from_brief(self, brief: dict) -> str:
        """从简报生成完整 PPT"""
        # 1. 选择最匹配的模板
        template = self._select_template(brief)

        # 2. 加载设计令牌
        tokens = self._load_tokens(template["tokens"])

        # 3. AI 生成内容
        content = await self._generate_content(brief, template)

        # 4. 构建 PPT
        builder = TemplateBuilder(tokens)
        for slide_config in template["slide_sequence"]:
            slide_content = content.get(slide_config["purpose"], {})
            self._build_slide(builder, slide_config, slide_content, tokens)

        # 5. 保存
        output_path = f"output/{brief['title']}.pptx"
        builder.save(output_path)
        return output_path

    def _select_template(self, brief: dict) -> dict:
        """根据简报选择最匹配的模板"""
        category = brief.get("category", "general")
        candidates = [
            t for t in self.registry["templates"]
            if t["category"] == category and t["status"] == "published"
        ]
        if not candidates:
            candidates = [
                t for t in self.registry["templates"]
                if t["status"] == "published"
            ]
        # 按使用量和评分排序
        candidates.sort(
            key=lambda t: (t["avg_rating"], t["usage_count"]),
            reverse=True
        )
        return candidates[0]

    async def _generate_content(self, brief: dict,
                                 template: dict) -> dict:
        """AI 生成每页内容"""
        preset = self._load_preset(template["preset"])
        content = {}

        for slide_config in preset["slide_sequence"]:
            purpose = slide_config["purpose"]
            hint = slide_config.get("content_hint", "")

            prompt = f"""Generate presentation slide content.

Topic: {brief['title']}
Audience: {brief.get('audience', 'general')}
Slide purpose: {purpose}
Content hint: {hint}
Variables needed: {slide_config['variables']}

Return JSON with the required variables filled in.
Keep text concise (max 6 bullet points, max 15 words each).
"""
            response = await self.llm.generate(prompt)
            content[purpose] = json.loads(response)

        return content

六、质量保障与测试

6.1 模板测试清单

模板质量检查清单:

视觉一致性:
- [ ] 所有页面使用统一的字体家族
- [ ] 颜色使用严格遵循设计令牌
- [ ] 标题/正文/标注的字号层级清晰
- [ ] 页边距和间距一致

内容适配:
- [ ] 标题区域能容纳 20 个中文字符
- [ ] 正文区域能容纳 6 条要点(每条 30 字)
- [ ] 图表区域在插入真实数据后不变形
- [ ] 表格在 5 列 x 8 行时仍可读

品牌合规:
- [ ] Logo 位置、大小正确
- [ ] 品牌色使用正确(主色 / 辅助色 / 强调色)
- [ ] 字体为品牌指定字体
- [ ] 页脚信息完整(公司名 / 保密声明)

技术规范:
- [ ] 文件大小 < 10MB(无嵌入视频时)
- [ ] 兼容 PowerPoint 2016+
- [ ] 兼容 WPS Office
- [ ] PDF 导出无布局错位

6.2 自动化测试

class TemplateValidator:
    """模板自动化校验"""

    def validate(self, pptx_path: str, tokens: dict) -> dict:
        """校验模板是否符合设计令牌"""
        prs = Presentation(pptx_path)
        issues = []

        for i, slide in enumerate(prs.slides):
            for shape in slide.shapes:
                if shape.has_text_frame:
                    for para in shape.text_frame.paragraphs:
                        for run in para.runs:
                            # 字体检查
                            allowed = [
                                tokens["typography"]["heading_family"],
                                tokens["typography"]["body_family"],
                                tokens["typography"]["mono_family"]
                            ]
                            if run.font.name and run.font.name not in allowed:
                                issues.append({
                                    "slide": i + 1,
                                    "type": "font",
                                    "detail": f"Unexpected font: {run.font.name}",
                                    "severity": "warning"
                                })

                            # 颜色检查
                            if run.font.color and run.font.color.rgb:
                                color = str(run.font.color.rgb)
                                allowed_colors = [
                                    v.lstrip("#").upper()
                                    for v in tokens["color"].values()
                                    if isinstance(v, str) and v.startswith("#")
                                ]
                                if color.upper() not in allowed_colors:
                                    issues.append({
                                        "slide": i + 1,
                                        "type": "color",
                                        "detail": f"Non-token color: #{color}",
                                        "severity": "info"
                                    })

        score = max(0, 100 - len(issues) * 3)
        return {
            "valid": score >= 80,
            "score": score,
            "issues": issues,
            "total_slides": len(prs.slides)
        }

七、部署与分发

7.1 模板分发策略

分发方式 适用场景 优势 劣势
Git 仓库 技术团队 版本控制、Code Review 非技术用户门槛高
内部网盘 全公司 简单、直观 版本混乱
模板平台 API 自动化系统 程序化访问 需要开发投入
Office 插件 个人用户 在 PPT 内选择 开发维护成本
品牌中心 品牌管理 集中管控 需要内容管理系统

7.2 版本管理

版本号规范:
  主版本.次版本.补丁版本

  主版本:品牌大改版(新 Logo、新配色方案)
  次版本:新增布局模板、新增变体
  补丁版本:修复对齐、修正字号、更新页脚

  示例:v2.1.3
    v2 = 品牌 2.0 升级
    .1 = 新增时间线布局
    .3 = 第三次微调

总结

PPT 模板工程的核心是把"视觉决策"从"内容填充"中分离出来。设计令牌是连接设计系统与程序化生成的桥梁:设计师维护令牌,工程师用令牌驱动模板构建,AI 用模板结构生成内容。关键设计决策三条:(1)令牌化一切视觉参数,(2)布局与内容解耦(布局模板 + 内容变量),(3)预设定义"故事结构"(页面顺序 + 内容提示),让 AI 生成的内容自然填入正确的框架。


Maurice | maurice_wen@proton.me