GKLBB

当你经历了暴风雨,你也就成为了暴风雨

导航

软件研发 --- AI应用开发 之 AI生PPT

我开发的项目

https://gitee.com/null_465_7266/aippt

存在的问题

如何将我上次的图片嵌入ppt中

我的解决方法是在提示词中描述图片素材来自 互联网的位置 并将材料上传到大模型,如果模型不支持就用图片描述替代模型的理解能力  例如 ,这是我的一图片请插入到ppt的对应的位置,https://xzimg.0573ol.com/20251114/ida1_1763092458728.png

效果如下

image

 

我的提问是

给我生成一个关于安卓逆向简介的PPT。

产品分析

豆包

image

 

讯飞

image

 

Gamma 

image

     优                        劣

       可以依据文档,模板,导入的现有ppt生成      无法依据网络收集高质量内容   

       可以生成风格一致的图片插入           内容质量混乱

       自定义内容

 Aippt     

收费

image

 

这是我能找的几款ai ppt产品,所有配置采用默认配置

个人感觉效果最好的依次是

 Aippt 

gamma

doubao

 

1.ai生成大致ppt两种方法,一种是依据已有模板生成内容后填充进去,一种是生成的自带样式

具体来讲

最好的解决方案是直接再ai大模型中就生成好ppt,但是我们普通人没有哪个能力,

其他解决方案有

ai操作每个ppt的绘制接口生成

内嵌式的格式转化ppt,比如我的提示词:  给我生成一个关于安卓逆向简介的PPT格式的网站页面,同时支持导出为pptx格式        这样提问的好处就是再生成html之初就嵌入pptx生成工具极大的简化了开发的难度,但是提升了模型的能力要求

用模板套用,依据模板的格式生成ppt的内容填充进去,这样的效果也不错,对模型的要求也不高

最差的是markdown转ppt,这样转换的只有图片和简单的字号大小

这里我采用的方案是

内嵌式的格式转化ppt

2.优化提示词,不同的提示词可以生成不同样式,比如

不加任何提示词时生成到的ppt是

image

 我们发现它的特点是深色背景,五颜六色的文字,带有表情文字,文字的整体框线方框中左侧带有醒目竖线

 通过优化提示词,明显可以发现样式提升了

极简提示词:

 给我生成一个关于安卓逆向简介的PPT格式的网站页面,同时支持导出为pptx格式

请美化样式,显示为简洁,清爽,大方,整个背景用白色,不要使用渐变色,不要使用浅色而是用正色,颜色和样式要统一

 复杂提示词: 

给我生成一个关于安卓逆向简介的PPT格式的网站页面,同时支持导出为pptx格式。

工具采用

const CDN_URLS = ['https://unpkg.com/pptxgenjs@4.0.1/dist/pptxgen.bundle.js'];

样式方面

请美化样式,显示为简洁,清爽,大方

真实感增强:

0. 界面尺寸应模拟苹果的MACbook的pc,并让界面圆角化,使其更像真实的电脑界面。

1. 使用真实的 UI 图片,而非占位符图片(可从 Unsplash、Pexels、Apple 官方 UI 资源中选择)。

2.不要使用任何渐变色,杂色和小图标,风格应该统一、美观、护眼、经典

3.文字颜色和背景颜色要统一,不要使用渐变色、五颜六色、花里胡哨的的文字

 生成的效果如下

image

 

 

image

 问题如下

ai理解成了将界面做成苹果界面

ppt设计呆板落后

 

依据上面问题,再次优化的提示词,

给我生成一个关于安卓逆向简介的PPT格式的网站页面,同时支持导出为pptx格式。

工具采用

const CDN_URLS = ['https://unpkg.com/pptxgenjs@4.0.1/dist/pptxgen.bundle.js'];

内容方面

1.文字内容要充实可行,拒绝空话套话抽象的话,用通俗语言解释

2.能用工具和数字证实的地方就快要尽可能用实用工具

样式方面

我的ppt要求如下 样式方面 请美化样式,显示为简洁,清爽,大方

ppt整体的设计界面尺寸应模拟苹果的MACbook的pc的大小布局设计

ppt整体的设计界面风格应该采用苹果电脑的ui设计规范,组件用透明玻璃效果,要充分展示ppt高级美感

ppt整体的设计使用真实的 UI 图片,而非占位符图片(可从 Unsplash、Pexels、Apple 官方 UI 资源中选择)。

ppt整体的设计不要使用任何渐变色,杂色,用正色,体现商务,正式,简约风格

ppt整体的设计风格应该统一、美观

ppt的背景不要使用深色这样不美观
 
claude sonnet回复

image

 

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>安卓逆向工程简介</title>
    <style>
        * {
            margin: 0;
            padding: 0;
            box-sizing: border-box;
        }

        body {
            font-family: -apple-system, BlinkMacSystemFont, 'SF Pro Display', 'Helvetica Neue', Arial, sans-serif;
            background: #f5f5f7;
            min-height: 100vh;
            color: #1d1d1f;
        }

        /* 顶部控制栏 */
        .top-bar {
            position: fixed;
            top: 0;
            left: 0;
            right: 0;
            z-index: 1000;
            height: 52px;
            background: rgba(255, 255, 255, 0.85);
            backdrop-filter: blur(20px);
            -webkit-backdrop-filter: blur(20px);
            border-bottom: 1px solid rgba(0, 0, 0, 0.08);
            display: flex;
            align-items: center;
            justify-content: space-between;
            padding: 0 24px;
        }

        .top-bar-left {
            display: flex;
            align-items: center;
            gap: 12px;
        }

        .app-icon {
            width: 28px;
            height: 28px;
            background: #000;
            border-radius: 7px;
            display: flex;
            align-items: center;
            justify-content: center;
            color: white;
            font-size: 14px;
            font-weight: 700;
        }

        .app-title {
            font-size: 14px;
            font-weight: 600;
            color: #1d1d1f;
            letter-spacing: -0.2px;
        }

        .top-bar-center {
            display: flex;
            align-items: center;
            gap: 8px;
        }

        .slide-indicator {
            font-size: 13px;
            color: #6e6e73;
            font-weight: 500;
        }

        .nav-btn {
            width: 28px;
            height: 28px;
            border: none;
            background: rgba(0, 0, 0, 0.06);
            border-radius: 6px;
            cursor: pointer;
            display: flex;
            align-items: center;
            justify-content: center;
            color: #1d1d1f;
            font-size: 12px;
            transition: all 0.2s;
        }

        .nav-btn:hover {
            background: rgba(0, 0, 0, 0.12);
        }

        .export-btn {
            height: 32px;
            padding: 0 16px;
            background: #000;
            color: white;
            border: none;
            border-radius: 8px;
            font-size: 13px;
            font-weight: 600;
            cursor: pointer;
            display: flex;
            align-items: center;
            gap: 6px;
            transition: all 0.2s;
            letter-spacing: -0.2px;
        }

        .export-btn:hover {
            background: #333;
            transform: translateY(-1px);
        }

        .export-btn:active {
            transform: translateY(0);
        }

        /* 左侧缩略图栏 */
        .sidebar {
            position: fixed;
            left: 0;
            top: 52px;
            bottom: 0;
            width: 180px;
            background: rgba(255, 255, 255, 0.7);
            backdrop-filter: blur(20px);
            -webkit-backdrop-filter: blur(20px);
            border-right: 1px solid rgba(0, 0, 0, 0.08);
            overflow-y: auto;
            padding: 16px 12px;
            display: flex;
            flex-direction: column;
            gap: 8px;
        }

        .sidebar::-webkit-scrollbar {
            width: 4px;
        }

        .sidebar::-webkit-scrollbar-track {
            background: transparent;
        }

        .sidebar::-webkit-scrollbar-thumb {
            background: rgba(0, 0, 0, 0.15);
            border-radius: 2px;
        }

        .thumb-item {
            cursor: pointer;
            border-radius: 8px;
            overflow: hidden;
            border: 2px solid transparent;
            transition: all 0.2s;
            background: white;
            box-shadow: 0 1px 4px rgba(0, 0, 0, 0.08);
        }

        .thumb-item:hover {
            border-color: rgba(0, 0, 0, 0.2);
        }

        .thumb-item.active {
            border-color: #000;
            box-shadow: 0 2px 12px rgba(0, 0, 0, 0.15);
        }

        .thumb-inner {
            width: 100%;
            aspect-ratio: 16/9;
            padding: 6px;
            display: flex;
            flex-direction: column;
            justify-content: center;
            align-items: flex-start;
            position: relative;
            overflow: hidden;
        }

        .thumb-num {
            position: absolute;
            bottom: 4px;
            right: 6px;
            font-size: 9px;
            color: #6e6e73;
            font-weight: 600;
        }

        .thumb-title {
            font-size: 7px;
            font-weight: 700;
            color: #1d1d1f;
            line-height: 1.2;
            max-width: 100%;
            overflow: hidden;
        }

        .thumb-subtitle {
            font-size: 5px;
            color: #6e6e73;
            margin-top: 2px;
        }

        /* 主内容区 */
        .main-content {
            margin-left: 180px;
            margin-top: 52px;
            padding: 40px;
            display: flex;
            flex-direction: column;
            align-items: center;
            min-height: calc(100vh - 52px);
        }

        /* PPT 幻灯片容器 */
        .slide-wrapper {
            width: 100%;
            max-width: 960px;
            position: relative;
        }

        .slide {
            display: none;
            width: 100%;
            aspect-ratio: 16/9;
            background: white;
            border-radius: 16px;
            box-shadow: 0 4px 24px rgba(0, 0, 0, 0.08), 0 1px 4px rgba(0, 0, 0, 0.04);
            overflow: hidden;
            position: relative;
            animation: slideIn 0.3s ease;
        }

        .slide.active {
            display: block;
        }

        @keyframes slideIn {
            from {
                opacity: 0;
                transform: translateY(8px);
            }
            to {
                opacity: 1;
                transform: translateY(0);
            }
        }

        /* ============================================
           幻灯片内部样式
        ============================================ */

        /* 通用布局 */
        .slide-content {
            width: 100%;
            height: 100%;
            padding: 48px 56px;
            display: flex;
            flex-direction: column;
            position: relative;
        }

        /* 装饰线条 */
        .accent-line {
            width: 40px;
            height: 3px;
            background: #000;
            border-radius: 2px;
            margin-bottom: 16px;
        }

        /* 标题幻灯片 - Slide 1 */
        .slide-1 {
            background: #ffffff;
        }

        .slide-1 .content-area {
            width: 100%;
            height: 100%;
            display: flex;
            flex-direction: column;
            justify-content: center;
            padding: 48px 56px;
            position: relative;
        }

        .slide-1 .bg-shape {
            position: absolute;
            top: -60px;
            right: -60px;
            width: 400px;
            height: 400px;
            border-radius: 50%;
            background: rgba(0, 0, 0, 0.03);
            pointer-events: none;
        }

        .slide-1 .bg-shape-2 {
            position: absolute;
            bottom: -80px;
            left: 40%;
            width: 300px;
            height: 300px;
            border-radius: 50%;
            background: rgba(0, 0, 0, 0.02);
            pointer-events: none;
        }

        .tag-badge {
            display: inline-flex;
            align-items: center;
            gap: 6px;
            background: #f5f5f7;
            border: 1px solid rgba(0, 0, 0, 0.08);
            border-radius: 20px;
            padding: 4px 12px;
            font-size: 11px;
            font-weight: 600;
            color: #6e6e73;
            letter-spacing: 0.4px;
            text-transform: uppercase;
            margin-bottom: 20px;
            width: fit-content;
        }

        .main-heading {
            font-size: 52px;
            font-weight: 700;
            color: #1d1d1f;
            letter-spacing: -2px;
            line-height: 1.05;
            margin-bottom: 16px;
        }

        .main-heading span {
            color: #6e6e73;
        }

        .sub-heading {
            font-size: 18px;
            color: #6e6e73;
            font-weight: 400;
            line-height: 1.5;
            max-width: 480px;
            letter-spacing: -0.3px;
        }

        .slide-1 .meta-row {
            position: absolute;
            bottom: 40px;
            left: 56px;
            display: flex;
            align-items: center;
            gap: 20px;
        }

        .meta-item {
            display: flex;
            align-items: center;
            gap: 6px;
            font-size: 12px;
            color: #6e6e73;
            font-weight: 500;
        }

        .meta-dot {
            width: 4px;
            height: 4px;
            border-radius: 50%;
            background: #d2d2d7;
        }

        .slide-1 .right-visual {
            position: absolute;
            right: 56px;
            top: 50%;
            transform: translateY(-50%);
            width: 280px;
        }

        .glass-card {
            background: rgba(255, 255, 255, 0.7);
            backdrop-filter: blur(20px);
            -webkit-backdrop-filter: blur(20px);
            border: 1px solid rgba(0, 0, 0, 0.08);
            border-radius: 16px;
            padding: 20px;
            box-shadow: 0 4px 20px rgba(0, 0, 0, 0.06);
        }

        .code-block {
            background: #f5f5f7;
            border-radius: 10px;
            padding: 14px;
            font-family: 'SF Mono', 'Fira Code', monospace;
            font-size: 11px;
            line-height: 1.6;
            color: #1d1d1f;
            border: 1px solid rgba(0, 0, 0, 0.06);
        }

        .code-line {
            display: block;
        }

        .code-comment {
            color: #6e6e73;
        }

        .code-keyword {
            color: #bf5af2;
        }

        .code-string {
            color: #34c759;
        }

        .code-function {
            color: #007aff;
        }

        /* 通用章节标题 */
        .section-header {
            margin-bottom: 32px;
        }

        .section-label {
            font-size: 11px;
            font-weight: 700;
            color: #6e6e73;
            letter-spacing: 1px;
            text-transform: uppercase;
            margin-bottom: 8px;
        }

        .section-title {
            font-size: 32px;
            font-weight: 700;
            color: #1d1d1f;
            letter-spacing: -1px;
            line-height: 1.1;
        }

        /* 卡片网格 */
        .card-grid {
            display: grid;
            gap: 16px;
        }

        .card-grid-2 {
            grid-template-columns: 1fr 1fr;
        }

        .card-grid-3 {
            grid-template-columns: 1fr 1fr 1fr;
        }

        .info-card {
            background: #f5f5f7;
            border-radius: 12px;
            padding: 20px;
            border: 1px solid rgba(0, 0, 0, 0.05);
            position: relative;
            overflow: hidden;
        }

        .info-card.glass {
            background: rgba(255, 255, 255, 0.6);
            backdrop-filter: blur(20px);
            -webkit-backdrop-filter: blur(20px);
            border: 1px solid rgba(0, 0, 0, 0.08);
            box-shadow: 0 2px 12px rgba(0, 0, 0, 0.04);
        }

        .card-icon {
            width: 36px;
            height: 36px;
            background: white;
            border-radius: 10px;
            display: flex;
            align-items: center;
            justify-content: center;
            font-size: 18px;
            margin-bottom: 12px;
            box-shadow: 0 1px 4px rgba(0, 0, 0, 0.08);
        }

        .card-title {
            font-size: 14px;
            font-weight: 700;
            color: #1d1d1f;
            margin-bottom: 6px;
            letter-spacing: -0.3px;
        }

        .card-desc {
            font-size: 12px;
            color: #6e6e73;
            line-height: 1.5;
            letter-spacing: -0.1px;
        }

        /* 工具列表 */
        .tool-list {
            display: flex;
            flex-direction: column;
            gap: 10px;
        }

        .tool-item {
            display: flex;
            align-items: center;
            gap: 14px;
            padding: 14px 16px;
            background: #f5f5f7;
            border-radius: 10px;
            border: 1px solid rgba(0, 0, 0, 0.05);
        }

        .tool-item.glass {
            background: rgba(255, 255, 255, 0.6);
            backdrop-filter: blur(20px);
            -webkit-backdrop-filter: blur(20px);
            border: 1px solid rgba(0, 0, 0, 0.08);
        }

        .tool-icon-box {
            width: 32px;
            height: 32px;
            background: white;
            border-radius: 8px;
            display: flex;
            align-items: center;
            justify-content: center;
            font-size: 16px;
            flex-shrink: 0;
            box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
        }

        .tool-info {
            flex: 1;
        }

        .tool-name {
            font-size: 13px;
            font-weight: 700;
            color: #1d1d1f;
            letter-spacing: -0.2px;
        }

        .tool-desc {
            font-size: 11px;
            color: #6e6e73;
            margin-top: 2px;
        }

        .tool-tag {
            font-size: 10px;
            font-weight: 600;
            color: #6e6e73;
            background: rgba(0, 0, 0, 0.06);
            padding: 2px 8px;
            border-radius: 4px;
            white-space: nowrap;
        }

        /* 流程步骤 */
        .step-flow {
            display: flex;
            align-items: flex-start;
            gap: 0;
            position: relative;
        }

        .step-item {
            flex: 1;
            display: flex;
            flex-direction: column;
            align-items: center;
            position: relative;
        }

        .step-connector {
            position: absolute;
            top: 18px;
            left: 50%;
            right: -50%;
            height: 1px;
            background: rgba(0, 0, 0, 0.1);
        }

        .step-num {
            width: 36px;
            height: 36px;
            border-radius: 50%;
            background: #1d1d1f;
            color: white;
            display: flex;
            align-items: center;
            justify-content: center;
            font-size: 14px;
            font-weight: 700;
            position: relative;
            z-index: 1;
            margin-bottom: 10px;
        }

        .step-title {
            font-size: 12px;
            font-weight: 700;
            color: #1d1d1f;
            text-align: center;
            margin-bottom: 4px;
        }

        .step-desc {
            font-size: 10px;
            color: #6e6e73;
            text-align: center;
            line-height: 1.4;
            padding: 0 4px;
        }

        /* 数据统计 */
        .stat-grid {
            display: grid;
            grid-template-columns: repeat(3, 1fr);
            gap: 16px;
        }

        .stat-card {
            background: #f5f5f7;
            border-radius: 12px;
            padding: 20px;
            text-align: center;
            border: 1px solid rgba(0, 0, 0, 0.05);
        }

        .stat-num {
            font-size: 32px;
            font-weight: 700;
            color: #1d1d1f;
            letter-spacing: -1px;
            line-height: 1;
            margin-bottom: 4px;
        }

        .stat-label {
            font-size: 11px;
            color: #6e6e73;
            font-weight: 500;
        }

        /* 对比表格 */
        .compare-table {
            width: 100%;
            border-collapse: separate;
            border-spacing: 0;
            font-size: 12px;
        }

        .compare-table th {
            background: #f5f5f7;
            padding: 10px 14px;
            font-weight: 700;
            color: #1d1d1f;
            text-align: left;
            border-bottom: 1px solid rgba(0, 0, 0, 0.08);
        }

        .compare-table th:first-child {
            border-radius: 8px 0 0 0;
        }

        .compare-table th:last-child {
            border-radius: 0 8px 0 0;
        }

        .compare-table td {
            padding: 10px 14px;
            color: #6e6e73;
            border-bottom: 1px solid rgba(0, 0, 0, 0.05);
        }

        .compare-table tr:last-child td {
            border-bottom: none;
        }

        .compare-table tr:nth-child(even) td {
            background: rgba(0, 0, 0, 0.01);
        }

        .tag-pill {
            display: inline-block;
            padding: 2px 8px;
            border-radius: 4px;
            font-size: 10px;
            font-weight: 600;
            background: rgba(0, 0, 0, 0.06);
            color: #6e6e73;
        }

        .tag-pill.highlight {
            background: #1d1d1f;
            color: white;
        }

        /* 底部页码 */
        .slide-footer {
            position: absolute;
            bottom: 24px;
            left: 56px;
            right: 56px;
            display: flex;
            align-items: center;
            justify-content: space-between;
        }

        .footer-brand {
            font-size: 11px;
            font-weight: 700;
            color: #d2d2d7;
            letter-spacing: 0.5px;
        }

        .footer-page {
            font-size: 11px;
            color: #d2d2d7;
            font-weight: 500;
        }

        .footer-line {
            flex: 1;
            height: 1px;
            background: rgba(0, 0, 0, 0.06);
            margin: 0 16px;
        }

        /* 进度指示器 */
        .slide-progress {
            display: flex;
            justify-content: center;
            gap: 6px;
            margin-top: 20px;
            flex-wrap: wrap;
        }

        .progress-dot {
            width: 6px;
            height: 6px;
            border-radius: 50%;
            background: rgba(0, 0, 0, 0.15);
            cursor: pointer;
            transition: all 0.2s;
        }

        .progress-dot.active {
            background: #000;
            transform: scale(1.3);
        }

        /* 键盘快捷键提示 */
        .keyboard-hint {
            text-align: center;
            margin-top: 12px;
            font-size: 11px;
            color: #6e6e73;
        }

        .kbd {
            display: inline-block;
            padding: 1px 6px;
            background: rgba(0, 0, 0, 0.06);
            border-radius: 4px;
            font-size: 10px;
            font-weight: 600;
            border: 1px solid rgba(0, 0, 0, 0.1);
        }

        /* 右侧面板 (for 2-col layouts) */
        .two-col {
            display: grid;
            grid-template-columns: 1fr 1fr;
            gap: 24px;
            flex: 1;
        }

        .col-left, .col-right {
            display: flex;
            flex-direction: column;
            gap: 12px;
        }

        /* 时间线 */
        .timeline {
            display: flex;
            flex-direction: column;
            gap: 0;
            position: relative;
        }

        .timeline::before {
            content: '';
            position: absolute;
            left: 15px;
            top: 16px;
            bottom: 16px;
            width: 1px;
            background: rgba(0, 0, 0, 0.1);
        }

        .timeline-item {
            display: flex;
            gap: 16px;
            padding: 8px 0;
            position: relative;
        }

        .timeline-dot {
            width: 31px;
            height: 31px;
            border-radius: 50%;
            background: white;
            border: 2px solid rgba(0, 0, 0, 0.15);
            display: flex;
            align-items: center;
            justify-content: center;
            font-size: 12px;
            flex-shrink: 0;
            position: relative;
            z-index: 1;
        }

        .timeline-dot.active-dot {
            border-color: #000;
            background: #000;
            color: white;
        }

        .timeline-content {
            flex: 1;
            padding-top: 4px;
        }

        .timeline-title {
            font-size: 13px;
            font-weight: 700;
            color: #1d1d1f;
        }

        .timeline-desc {
            font-size: 11px;
            color: #6e6e73;
            margin-top: 2px;
            line-height: 1.4;
        }

        /* 警告/提示框 */
        .alert-box {
            background: #fff8e1;
            border: 1px solid rgba(0, 0, 0, 0.08);
            border-radius: 10px;
            padding: 14px 16px;
            display: flex;
            gap: 10px;
            align-items: flex-start;
        }

        .alert-icon {
            font-size: 16px;
            flex-shrink: 0;
        }

        .alert-text {
            font-size: 12px;
            color: #6e6e73;
            line-height: 1.5;
        }

        .alert-text strong {
            color: #1d1d1f;
        }

        /* 大图片区 */
        .visual-panel {
            border-radius: 12px;
            overflow: hidden;
            position: relative;
            background: #f5f5f7;
        }

        .visual-panel img {
            width: 100%;
            height: 100%;
            object-fit: cover;
        }

        .visual-overlay {
            position: absolute;
            bottom: 0;
            left: 0;
            right: 0;
            background: rgba(255, 255, 255, 0.9);
            backdrop-filter: blur(10px);
            padding: 12px 16px;
        }

        .visual-overlay-title {
            font-size: 12px;
            font-weight: 700;
            color: #1d1d1f;
        }

        .visual-overlay-desc {
            font-size: 10px;
            color: #6e6e73;
        }

        /* 导出加载 */
        .export-loading {
            position: fixed;
            inset: 0;
            background: rgba(255, 255, 255, 0.9);
            backdrop-filter: blur(10px);
            display: flex;
            flex-direction: column;
            align-items: center;
            justify-content: center;
            z-index: 9999;
            gap: 16px;
        }

        .export-loading.hidden {
            display: none;
        }

        .loading-spinner {
            width: 40px;
            height: 40px;
            border: 3px solid rgba(0, 0, 0, 0.1);
            border-top-color: #000;
            border-radius: 50%;
            animation: spin 0.8s linear infinite;
        }

        @keyframes spin {
            to { transform: rotate(360deg); }
        }

        .loading-text {
            font-size: 16px;
            font-weight: 600;
            color: #1d1d1f;
        }

        .loading-sub {
            font-size: 13px;
            color: #6e6e73;
        }

        /* 响应式 */
        @media (max-width: 768px) {
            .sidebar { display: none; }
            .main-content { margin-left: 0; padding: 60px 16px 20px; }
        }
    </style>
</head>
<body>

<!-- 导出加载提示 -->
<div class="export-loading hidden" id="exportLoading">
    <div class="loading-spinner"></div>
    <div class="loading-text">正在生成 PPTX 文件</div>
    <div class="loading-sub">请稍候,这可能需要几秒钟...</div>
</div>

<!-- 顶部控制栏 -->
<div class="top-bar">
    <div class="top-bar-left">
        <div class="app-icon">AR</div>
        <div class="app-title">安卓逆向工程简介</div>
    </div>
    <div class="top-bar-center">
        <button class="nav-btn" onclick="prevSlide()" title="上一页">←</button>
        <span class="slide-indicator" id="slideIndicator">1 / 10</span>
        <button class="nav-btn" onclick="nextSlide()" title="下一页">→</button>
    </div>
    <button class="export-btn" onclick="exportPPTX()">
        ↓ 导出 PPTX
    </button>
</div>

<!-- 左侧缩略图 -->
<div class="sidebar" id="sidebar">
    <!-- 由 JS 生成 -->
</div>

<!-- 主内容区 -->
<div class="main-content">
    <div class="slide-wrapper">

        <!-- ======= SLIDE 1: 封面 ======= -->
        <div class="slide slide-1 active" id="slide-1">
            <div class="bg-shape"></div>
            <div class="bg-shape-2"></div>
            <div class="content-area">
                <div class="tag-badge">🔍 技术入门指南 · 2024</div>
                <div class="main-heading">安卓逆向<br><span>工程简介</span></div>
                <div class="sub-heading">了解 Android APK 如何被分析、解构与研究——从工具到流程,系统性入门</div>
                <div class="meta-row">
                    <div class="meta-item">🎯 适合初学者</div>
                    <div class="meta-dot"></div>
                    <div class="meta-item">📱 Android 平台</div>
                    <div class="meta-dot"></div>
                    <div class="meta-item">⏱ 预计阅读 15 分钟</div>
                </div>
            </div>
            <div class="right-visual">
                <div class="glass-card">
                    <div style="font-size:11px;font-weight:700;color:#1d1d1f;margin-bottom:10px;">📄 APK 结构</div>
                    <div class="code-block">
                        <span class="code-line"><span class="code-comment"># APK 本质是 ZIP 文件</span></span>
                        <span class="code-line">app.apk/</span>
                        <span class="code-line">├── <span class="code-function">classes.dex</span>   <span class="code-comment"># 代码</span></span>
                        <span class="code-line">├── <span class="code-string">res/</span>          <span class="code-comment"># 资源</span></span>
                        <span class="code-line">├── <span class="code-keyword">lib/</span>          <span class="code-comment"># SO库</span></span>
                        <span class="code-line">└── AndroidManifest.xml</span>
                    </div>
                </div>
            </div>
            <div class="slide-footer">
                <div class="footer-brand">ANDROID REVERSE</div>
                <div class="footer-line"></div>
                <div class="footer-page">01 / 10</div>
            </div>
        </div>

        <!-- ======= SLIDE 2: 什么是逆向工程 ======= -->
        <div class="slide" id="slide-2">
            <div class="slide-content">
                <div class="section-header">
                    <div class="section-label">Chapter 01</div>
                    <div class="accent-line"></div>
                    <div class="section-title">什么是安卓逆向工程?</div>
                </div>
                <div class="two-col" style="flex:1;">
                    <div class="col-left">
                        <div class="info-card glass" style="flex:1;">
                            <div class="card-icon">🔧</div>
                            <div class="card-title">通俗理解</div>
                            <div class="card-desc">
                                你下载了一个 APP,但没有源代码。逆向工程就是把这个 APP 的 <strong style="color:#1d1d1f">classes.dex(编译后的代码文件)</strong> 还原回你能读懂的 Java/Smali 代码,就像把熟食还原成菜谱。
                            </div>
                        </div>
                        <div class="info-card glass" style="flex:1;">
                            <div class="card-icon">⚖️</div>
                            <div class="card-title">合法场景</div>
                            <div class="card-desc">
                                • 安全研究:发现 APP 漏洞并上报<br>
                                • 恶意软件分析:看病毒干了什么<br>
                                • 兼容性测试:协议分析<br>
                                • 自己的 APP:忘记源码时恢复
                            </div>
                        </div>
                    </div>
                    <div class="col-right">
                        <div class="info-card" style="background:#f5f5f7;flex:1;">
                            <div style="font-size:12px;font-weight:700;color:#1d1d1f;margin-bottom:12px;">📦 Android 代码编译链</div>
                            <div style="display:flex;flex-direction:column;gap:6px;">
                                <div style="background:white;border-radius:8px;padding:10px 14px;border:1px solid rgba(0,0,0,0.06);">
                                    <div style="font-size:11px;font-weight:700;color:#1d1d1f;">.java / .kt 源码</div>
                                    <div style="font-size:10px;color:#6e6e73;">开发者写的代码</div>
                                </div>
                                <div style="text-align:center;font-size:11px;color:#6e6e73;">↓ javac / kotlinc 编译</div>
                                <div style="background:white;border-radius:8px;padding:10px 14px;border:1px solid rgba(0,0,0,0.06);">
                                    <div style="font-size:11px;font-weight:700;color:#1d1d1f;">.class 字节码</div>
                                    <div style="font-size:10px;color:#6e6e73;">JVM 字节码</div>
                                </div>
                                <div style="text-align:center;font-size:11px;color:#6e6e73;">↓ d8 / dx 转换</div>
                                <div style="background:#1d1d1f;border-radius:8px;padding:10px 14px;">
                                    <div style="font-size:11px;font-weight:700;color:white;">classes.dex</div>
                                    <div style="font-size:10px;color:rgba(255,255,255,0.5);">Dalvik 字节码 — 逆向目标</div>
                                </div>
                            </div>
                        </div>
                    </div>
                </div>
                <div class="slide-footer">
                    <div class="footer-brand">ANDROID REVERSE</div>
                    <div class="footer-line"></div>
                    <div class="footer-page">02 / 10</div>
                </div>
            </div>
        </div>

        <!-- ======= SLIDE 3: 核心工具 ======= -->
        <div class="slide" id="slide-3">
            <div class="slide-content">
                <div class="section-header">
                    <div class="section-label">Chapter 02</div>
                    <div class="accent-line"></div>
                    <div class="section-title">必备逆向工具全景</div>
                </div>
                <div class="tool-list" style="flex:1;justify-content:center;gap:8px;">
                    <div class="tool-item glass">
                        <div class="tool-icon-box">🔓</div>
                        <div class="tool-info">
                            <div class="tool-name">jadx</div>
                            <div class="tool-desc">把 APK/dex 直接反编译成可读的 Java 代码,带 GUI 界面,是新手首选工具</div>
                        </div>
                        <div class="tool-tag">反编译</div>
                    </div>
                    <div class="tool-item glass">
                        <div class="tool-icon-box">🔨</div>
                        <div class="tool-info">
                            <div class="tool-name">apktool</div>
                            <div class="tool-desc">解包 APK → 修改 Smali 代码 → 重新打包。版本 v2.9.3,用于修改和回编译</div>
                        </div>
                        <div class="tool-tag">重打包</div>
                    </div>
                    <div class="tool-item glass">
                        <div class="tool-icon-box">🕵️</div>
                        <div class="tool-info">
                            <div class="tool-name">Frida</div>
                            <div class="tool-desc">动态插桩框架,用 JS 脚本在运行中 hook 任意函数,实时修改返回值,最强动态分析工具</div>
                        </div>
                        <div class="tool-tag">动态分析</div>
                    </div>
                    <div class="tool-item glass">
                        <div class="tool-icon-box">🌐</div>
                        <div class="tool-info">
                            <div class="tool-name">Charles / mitmproxy</div>
                            <div class="tool-desc">抓取 APP 的 HTTPS 网络请求,看它偷偷发了什么数据到服务器</div>
                        </div>
                        <div class="tool-tag">流量分析</div>
                    </div>
                    <div class="tool-item glass">
                        <div class="tool-icon-box">🏗️</div>
                        <div class="tool-info">
                            <div class="tool-name">IDA Pro / Ghidra</div>
                            <div class="tool-desc">分析 .so 原生库(C/C++ 编译的 ARM 代码),Ghidra 免费开源,NSA 出品</div>
                        </div>
                        <div class="tool-tag">Native 分析</div>
                    </div>
                </div>
                <div class="slide-footer">
                    <div class="footer-brand">ANDROID REVERSE</div>
                    <div class="footer-line"></div>
                    <div class="footer-page">03 / 10</div>
                </div>
            </div>
        </div>

        <!-- ======= SLIDE 4: 逆向工作流 ======= -->
        <div class="slide" id="slide-4">
            <div class="slide-content">
                <div class="section-header">
                    <div class="section-label">Chapter 03</div>
                    <div class="accent-line"></div>
                    <div class="section-title">标准逆向分析流程</div>
                </div>
                <div class="step-flow" style="margin-bottom:24px;">
                    <div class="step-item">
                        <div class="step-num">1</div>
                        <div class="step-connector"></div>
                        <div class="step-title">获取 APK</div>
                        <div class="step-desc">adb pull 或从手机提取,使用 APKPure 等平台</div>
                    </div>
                    <div class="step-item">
                        <div class="step-num">2</div>
                        <div class="step-connector"></div>
                        <div class="step-title">静态分析</div>
                        <div class="step-desc">用 jadx 查看代码结构、权限声明、关键类</div>
                    </div>
                    <div class="step-item">
                        <div class="step-num">3</div>
                        <div class="step-connector"></div>
                        <div class="step-title">定位目标</div>
                        <div class="step-desc">搜索关键词如 "login" "check" "encrypt"</div>
                    </div>
                    <div class="step-item">
                        <div class="step-num">4</div>
                        <div class="step-connector"></div>
                        <div class="step-title">动态验证</div>
                        <div class="step-desc">Frida hook 目标函数,打印实参和返回值</div>
                    </div>
                    <div class="step-item">
                        <div class="step-num">5</div>
                        <div style="display:none" class="step-connector"></div>
                        <div class="step-title">整理结论</div>
                        <div class="step-desc">记录发现的逻辑、接口、加密算法</div>
                    </div>
                </div>
                <div class="card-grid card-grid-3" style="flex:1;align-content:start;gap:12px;">
                    <div class="info-card glass">
                        <div class="card-title">🔍 常用 adb 命令</div>
                        <div class="code-block" style="font-size:10px;">
                            <span class="code-line"><span class="code-comment"># 列出设备包名</span></span>
                            <span class="code-line">adb shell pm list packages</span>
                            <span class="code-line"></span>
                            <span class="code-line"><span class="code-comment"># 提取 APK</span></span>
                            <span class="code-line">adb pull /data/app/xxx/base.apk</span>
                        </div>
                    </div>
                    <div class="info-card glass">
                        <div class="card-title">🪝 Frida Hook 模板</div>
                        <div class="code-block" style="font-size:10px;">
                            <span class="code-line">Java.perform(<span class="code-keyword">function</span>() {</span>
                            <span class="code-line">  <span class="code-keyword">var</span> Cls = Java.use(<span class="code-string">"com.app.Login"</span>);</span>
                            <span class="code-line">  Cls.check.implementation = <span class="code-keyword">function</span>() {</span>
                            <span class="code-line">    <span class="code-keyword">return</span> <span class="code-function">true</span>; <span class="code-comment">// 绕过</span></span>
                            <span class="code-line">  };</span>
                            <span class="code-line">});</span>
                        </div>
                    </div>
                    <div class="info-card glass">
                        <div class="card-title">📋 分析清单</div>
                        <div style="display:flex;flex-direction:column;gap:4px;">
                            <div style="font-size:11px;color:#6e6e73;display:flex;gap:6px;align-items:center;"><span>☑</span> AndroidManifest 权限</div>
                            <div style="font-size:11px;color:#6e6e73;display:flex;gap:6px;align-items:center;"><span>☑</span> 网络请求地址</div>
                            <div style="font-size:11px;color:#6e6e73;display:flex;gap:6px;align-items:center;"><span>☑</span> 本地存储内容</div>
                            <div style="font-size:11px;color:#6e6e73;display:flex;gap:6px;align-items:center;"><span>☑</span> 加密算法类型</div>
                            <div style="font-size:11px;color:#6e6e73;display:flex;gap:6px;align-items:center;"><span>☑</span> 混淆程度评估</div>
                        </div>
                    </div>
                </div>
                <div class="slide-footer">
                    <div class="footer-brand">ANDROID REVERSE</div>
                    <div class="footer-line"></div>
                    <div class="footer-page">04 / 10</div>
                </div>
            </div>
        </div>

        <!-- ======= SLIDE 5: Smali 语言 ======= -->
        <div class="slide" id="slide-5">
            <div class="slide-content">
                <div class="section-header">
                    <div class="section-label">Chapter 04</div>
                    <div class="accent-line"></div>
                    <div class="section-title">读懂 Smali —— 安卓汇编语言</div>
                </div>
                <div class="two-col" style="flex:1;">
                    <div>
                        <div style="font-size:12px;font-weight:700;color:#6e6e73;margin-bottom:8px;">原始 Java 代码</div>
                        <div class="code-block" style="font-size:11px;line-height:1.7;">
                            <span class="code-line"><span class="code-keyword">public boolean</span> <span class="code-function">isVip</span>(String uid) {</span>
                            <span class="code-line">  <span class="code-keyword">if</span> (uid.equals(<span class="code-string">"admin"</span>)) {</span>
                            <span class="code-line">    <span class="code-keyword">return true</span>;</span>
                            <span class="code-line">  }</span>
                            <span class="code-line">  <span class="code-keyword">return false</span>;</span>
                            <span class="code-line">}</span>
                        </div>
                        <div style="margin-top:16px;font-size:12px;font-weight:700;color:#6e6e73;margin-bottom:8px;">关键寄存器规则</div>
                        <div style="display:flex;flex-direction:column;gap:6px;">
                            <div style="background:#f5f5f7;border-radius:8px;padding:8px 12px;font-size:11px;display:flex;gap:12px;">
                                <span style="font-family:monospace;font-weight:700;color:#1d1d1f;min-width:32px;">v0</span>
                                <span style="color:#6e6e73;">本地变量寄存器,从 v0 开始编号</span>
                            </div>
                            <div style="background:#f5f5f7;border-radius:8px;padding:8px 12px;font-size:11px;display:flex;gap:12px;">
                                <span style="font-family:monospace;font-weight:700;color:#1d1d1f;min-width:32px;">p0</span>
                                <span style="color:#6e6e73;">参数寄存器,p0 = this(对象方法)</span>
                            </div>
                            <div style="background:#f5f5f7;border-radius:8px;padding:8px 12px;font-size:11px;display:flex;gap:12px;">
                                <span style="font-family:monospace;font-weight:700;color:#1d1d1f;min-width:32px;">p1</span>
                                <span style="color:#6e6e73;">第一个参数,上例中 p1 = uid</span>
                            </div>
                        </div>
                    </div>
                    <div>
                        <div style="font-size:12px;font-weight:700;color:#6e6e73;margin-bottom:8px;">对应 Smali 代码</div>
                        <div class="code-block" style="font-size:10px;line-height:1.7;">
                            <span class="code-line"><span class="code-comment">.method public isVip(Ljava/lang/String;)Z</span></span>
                            <span class="code-line">  .registers 3 <span class="code-comment"># v0, p0(this), p1(uid)</span></span>
                            <span class="code-line"></span>
                            <span class="code-line">  const-string v0, <span class="code-string">"admin"</span></span>
                            <span class="code-line">  invoke-virtual {p1, v0},</span>
                            <span class="code-line">    Ljava/lang/String;->equals(Ljava/lang/Object;)Z</span>
                            <span class="code-line">  move-result v0</span>
                            <span class="code-line">  <span class="code-keyword">if-eqz</span> v0, :cond_0 <span class="code-comment"># 若不等则跳转</span></span>
                            <span class="code-line"></span>
                            <span class="code-line">  const/4 v0, <span class="code-function">0x1</span>  <span class="code-comment"># true</span></span>
                            <span class="code-line">  return v0</span>
                            <span class="code-line"></span>
                            <span class="code-line">  :cond_0</span>
                            <span class="code-line">  const/4 v0, <span class="code-function">0x0</span>  <span class="code-comment"># false</span></span>
                            <span class="code-line">  return v0</span>
                            <span class="code-line">.end method</span>
                        </div>
                        <div style="margin-top:10px;" class="alert-box">
                            <div class="alert-icon">💡</div>
                            <div class="alert-text">把 <strong>if-eqz 改成 if-nez</strong>,或直接把 const/4 v0, 0x0 改成 0x1,即可绕过验证</div>
                        </div>
                    </div>
                </div>
                <div class="slide-footer">
                    <div class="footer-brand">ANDROID REVERSE</div>
                    <div class="footer-line"></div>
                    <div class="footer-page">05 / 10</div>
                </div>
            </div>
        </div>

        <!-- ======= SLIDE 6: 常见保护手段 ======= -->
        <div class="slide" id="slide-6">
            <div class="slide-content">
                <div class="section-header">
                    <div class="section-label">Chapter 05</div>
                    <div class="accent-line"></div>
                    <div class="section-title">APP 的 6 大保护机制</div>
                </div>
                <div class="card-grid card-grid-3" style="flex:1;gap:12px;align-content:start;">
                    <div class="info-card glass">
                        <div class="card-icon">🌫️</div>
                        <div class="card-title">代码混淆 (ProGuard)</div>
                        <div class="card-desc">把 <code style="font-size:10px;background:#f0f0f0;padding:1px 4px;border-radius:3px;">LoginActivity</code> 改成 <code style="font-size:10px;background:#f0f0f0;padding:1px 4px;border-radius:3px;">a.b.c</code>,增加阅读难度,但逻辑不变,jadx 仍可反编译</div>
                    </div>
                    <div class="info-card glass">
                        <div class="card-icon">📦</div>
                        <div class="card-title">加壳 (Packing)</div>
                        <div class="card-desc">把真正的 dex 加密后隐藏,运行时再解密。常见壳:梆梆、360加固、腾讯乐固。需要先脱壳再分析</div>
                    </div>
                    <div class="info-card glass">
                        <div class="card-icon">🔐</div>
                        <div class="card-title">SSL Pinning</div>
                        <div class="card-desc">APP 内置证书指纹,只接受特定证书,阻止中间人抓包。可用 Frida 脚本或 TrustMeAlready 模块绕过</div>
                    </div>
                    <div class="info-card glass">
                        <div class="card-icon">🔍</div>
                        <div class="card-title">Root / 调试检测</div>
                        <div class="card-desc">检测 /system/bin/su 文件是否存在、是否可被调试。可用 Magisk DenyList 或 RootBeer 绕过模块对抗</div>
                    </div>
                    <div class="info-card glass">
                        <div class="card-icon">⚡</div>
                        <div class="card-title">VMP 虚拟机保护</div>
                        <div class="card-desc">核心算法被自定义虚拟机解释执行,指令集完全私有,是目前最难破解的保护方式</div>
                    </div>
                    <div class="info-card glass">
                        <div class="card-icon">✅</div>
                        <div class="card-title">签名校验</div>
                        <div class="card-desc">APP 运行时校验自身签名,修改 smali 重打包后签名变了会直接闪退。需 hook <code style="font-size:10px;background:#f0f0f0;padding:1px 4px;border-radius:3px;">getSignatures</code> 返回原始值</div>
                    </div>
                </div>
                <div class="slide-footer">
                    <div class="footer-brand">ANDROID REVERSE</div>
                    <div class="footer-line"></div>
                    <div class="footer-page">06 / 10</div>
                </div>
            </div>
        </div>

        <!-- ======= SLIDE 7: 动态分析 Frida ======= -->
        <div class="slide" id="slide-7">
            <div class="slide-content">
                <div class="section-header">
                    <div class="section-label">Chapter 06</div>
                    <div class="accent-line"></div>
                    <div class="section-title">Frida 动态分析实战</div>
                </div>
                <div class="two-col" style="flex:1;">
                    <div style="display:flex;flex-direction:column;gap:12px;">
                        <div class="info-card" style="background:#f5f5f7;">
                            <div style="font-size:12px;font-weight:700;color:#1d1d1f;margin-bottom:8px;">① 环境搭建</div>
                            <div class="code-block" style="font-size:10px;line-height:1.7;">
                                <span class="code-line"><span class="code-comment"># 安装 frida 工具</span></span>
                                <span class="code-line">pip install frida-tools</span>
                                <span class="code-line"></span>
                                <span class="code-line"><span class="code-comment"># 推送 frida-server 到手机</span></span>
                                <span class="code-line">adb push frida-server /data/local/tmp/</span>
                                <span class="code-line">adb shell "chmod 755 /data/local/tmp/frida-server"</span>
                                <span class="code-line">adb shell "/data/local/tmp/frida-server &"</span>
                            </div>
                        </div>
                        <div class="info-card" style="background:#f5f5f7;">
                            <div style="font-size:12px;font-weight:700;color:#1d1d1f;margin-bottom:8px;">② 注入脚本</div>
                            <div class="code-block" style="font-size:10px;line-height:1.7;">
                                <span class="code-line"><span class="code-comment"># 对目标包名注入脚本</span></span>
                                <span class="code-line">frida -U -f <span class="code-string">com.target.app</span> \</span>
                                <span class="code-line">  -l <span class="code-string">hook.js</span> --no-pause</span>
                            </div>
                        </div>
                    </div>
                    <div style="display:flex;flex-direction:column;gap:12px;">
                        <div class="info-card" style="background:#f5f5f7;flex:1;">
                            <div style="font-size:12px;font-weight:700;color:#1d1d1f;margin-bottom:8px;">③ Hook 实战脚本:追踪加密函数</div>
                            <div class="code-block" style="font-size:10px;line-height:1.7;">
                                <span class="code-line">Java.perform(<span class="code-keyword">function</span>() {</span>
                                <span class="code-line">  <span class="code-comment">// Hook MessageDigest (MD5/SHA)</span></span>
                                <span class="code-line">  <span class="code-keyword">var</span> MD = Java.use(<span class="code-string">"java.security.MessageDigest"</span>);</span>
                                <span class="code-line">  MD.update.overload(<span class="code-string">"[B"</span>).implementation = <span class="code-keyword">function</span>(b) {</span>
                                <span class="code-line">    console.log(<span class="code-string">"[*] MD input: "</span> + Java.use(<span class="code-string">"java.lang.String"</span>)</span>
                                <span class="code-line">      .$new(b));</span>
                                <span class="code-line">    <span class="code-keyword">return</span> <span class="code-function">this</span>.update(b);</span>
                                <span class="code-line">  };</span>
                                <span class="code-line"></span>
                                <span class="code-line">  <span class="code-comment">// 查看调用栈,定位代码位置</span></span>
                                <span class="code-line">  console.log(Java.use(<span class="code-string">"android.util.Log"</span>)</span>
                                <span class="code-line">    .getStackTraceString(</span>
                                <span class="code-line">      Java.use(<span class="code-string">"java.lang.Exception"</span>).$new()));</span>
                                <span class="code-line">});</span>
                            </div>
                        </div>
                    </div>
                </div>
                <div class="slide-footer">
                    <div class="footer-brand">ANDROID REVERSE</div>
                    <div class="footer-line"></div>
                    <div class="footer-page">07 / 10</div>
                </div>
            </div>
        </div>

        <!-- ======= SLIDE 8: 数据与行业现状 ======= -->
        <div class="slide" id="slide-8">
            <div class="slide-content">
                <div class="section-header">
                    <div class="section-label">Chapter 07</div>
                    <div class="accent-line"></div>
                    <div class="section-title">行业数据与应用现状</div>
                </div>
                <div class="stat-grid" style="margin-bottom:20px;">
                    <div class="stat-card">
                        <div class="stat-num">35%</div>
                        <div class="stat-label">Google Play 上架 APP 使用了 ProGuard 混淆<br><span style="font-size:10px;color:#aaa;">(NowSecure 2023 报告)</span></div>
                    </div>
                    <div class="stat-card">
                        <div class="stat-num">73%</div>
                        <div class="stat-label">金融类 APP 存在至少一个高危安全漏洞<br><span style="font-size:10px;color:#aaa;">(OWASP Mobile Top 10 统计)</span></div>
                    </div>
                    <div class="stat-card">
                        <div class="stat-num">$38K</div>
                        <div class="stat-label">Google 安卓漏洞最高 Bug Bounty 奖励<br><span style="font-size:10px;color:#aaa;">(Google VRP 2023)</span></div>
                    </div>
                </div>
                <div class="two-col" style="flex:1;gap:16px;">
                    <div class="info-card glass">
                        <div class="card-title">📊 逆向工程主要应用场景</div>
                        <div style="margin-top:10px;display:flex;flex-direction:column;gap:8px;">
                            <div>
                                <div style="display:flex;justify-content:space-between;font-size:11px;margin-bottom:3px;">
                                    <span style="color:#1d1d1f;font-weight:600;">安全漏洞研究</span>
                                    <span style="color:#6e6e73;">45%</span>
                                </div>
                                <div style="height:4px;background:#f0f0f0;border-radius:2px;overflow:hidden;">
                                    <div style="width:45%;height:100%;background:#1d1d1f;border-radius:2px;"></div>
                                </div>
                            </div>
                            <div>
                                <div style="display:flex;justify-content:space-between;font-size:11px;margin-bottom:3px;">
                                    <span style="color:#1d1d1f;font-weight:600;">恶意软件分析</span>
                                    <span style="color:#6e6e73;">30%</span>
                                </div>
                                <div style="height:4px;background:#f0f0f0;border-radius:2px;overflow:hidden;">
                                    <div style="width:30%;height:100%;background:#1d1d1f;border-radius:2px;"></div>
                                </div>
                            </div>
                            <div>
                                <div style="display:flex;justify-content:space-between;font-size:11px;margin-bottom:3px;">
                                    <span style="color:#1d1d1f;font-weight:600;">协议还原分析</span>
                                    <span style="color:#6e6e73;">15%</span>
                                </div>
                                <div style="height:4px;background:#f0f0f0;border-radius:2px;overflow:hidden;">
                                    <div style="width:15%;height:100%;background:#1d1d1f;border-radius:2px;"></div>
                                </div>
                            </div>
                            <div>
                                <div style="display:flex;justify-content:space-between;font-size:11px;margin-bottom:3px;">
                                    <span style="color:#1d1d1f;font-weight:600;">其他(兼容/测试)</span>
                                    <span style="color:#6e6e73;">10%</span>
                                </div>
                                <div style="height:4px;background:#f0f0f0;border-radius:2px;overflow:hidden;">
                                    <div style="width:10%;height:100%;background:#1d1d1f;border-radius:2px;"></div>
                                </div>
                            </div>
                        </div>
                    </div>
                    <div class="info-card glass">
                        <div class="card-title">🏆 学习资源推荐</div>
                        <div style="margin-top:10px;display:flex;flex-direction:column;gap:8px;">
                            <div style="padding:8px 12px;background:#f5f5f7;border-radius:8px;font-size:11px;">
                                <div style="font-weight:700;color:#1d1d1f;">CTF 平台</div>
                                <div style="color:#6e6e73;margin-top:2px;">BUUCTF、攻防世界均有专项 Android 题目</div>
                            </div>
                            <div style="padding:8px 12px;background:#f5f5f7;border-radius:8px;font-size:11px;">
                                <div style="font-weight:700;color:#1d1d1f;">OWASP MASTG</div>
                                <div style="color:#6e6e73;margin-top:2px;">移动安全测试指南,官方免费 PDF,系统性最强</div>
                            </div>
                            <div style="padding:8px 12px;background:#f5f5f7;border-radius:8px;font-size:11px;">
                                <div style="font-weight:700;color:#1d1d1f;">看雪论坛 / 52pojie</div>
                                <div style="color:#6e6e73;margin-top:2px;">国内最活跃的逆向社区,有大量实战案例</div>
                            </div>
                            <div style="padding:8px 12px;background:#f5f5f7;border-radius:8px;font-size:11px;">
                                <div style="font-weight:700;color:#1d1d1f;">Android Internals(书)</div>
                                <div style="color:#6e6e73;margin-top:2px;">Jonathan Levin 著,深入 Android 系统底层原理</div>
                            </div>
                        </div>
                    </div>
                </div>
                <div class="slide-footer">
                    <div class="footer-brand">ANDROID REVERSE</div>
                    <div class="footer-line"></div>
                    <div class="footer-page">08 / 10</div>
                </div>
            </div>
        </div>

        <!-- ======= SLIDE 9: 法律与道德 ======= -->
        <div class="slide" id="slide-9">
            <div class="slide-content">
                <div class="section-header">
                    <div class="section-label">Chapter 08</div>
                    <div class="accent-line"></div>
                    <div class="section-title">法律红线与职业道德</div>
                </div>
                <div style="flex:1;display:flex;flex-direction:column;gap:14px;">
                    <table class="compare-table" style="background:white;border-radius:10px;overflow:hidden;border:1px solid rgba(0,0,0,0.06);">
                        <thead>
                            <tr>
                                <th style="width:30%">行为</th>
                                <th style="width:25%">法律依据(中国)</th>
                                <th style="width:20%">风险等级</th>
                                <th style="width:25%">建议</th>
                            </tr>
                        </thead>
                        <tbody>
                            <tr>
                                <td>分析自己的 APP / 授权安全测试</td>
                                <td>合法行为</td>
                                <td><span class="tag-pill highlight">✓ 安全</span></td>
                                <td>推荐练习方式</td>
                            </tr>
                            <tr>
                                <td>CTF 竞赛逆向题</td>
                                <td>合法行为</td>
                                <td><span class="tag-pill highlight">✓ 安全</span></td>
                                <td>最佳入门途径</td>
                            </tr>
                            <tr>
                                <td>发现漏洞后负责任披露</td>
                                <td>《网络安全法》鼓励</td>
                                <td><span class="tag-pill highlight">✓ 鼓励</span></td>
                                <td>可获 Bug Bounty 奖励</td>
                            </tr>
                            <tr>
                                <td>破解商业软件版权保护</td>
                                <td>《著作权法》第 48 条</td>
                                <td><span class="tag-pill">⚠ 违法</span></td>
                                <td>可能面临民事赔偿</td>
                            </tr>
                            <tr>
                                <td>未授权入侵、窃取数据</td>
                                <td>《刑法》285/286 条</td>
                                <td><span class="tag-pill">🚫 刑事</span></td>
                                <td>最高 7 年有期徒刑</td>
                            </tr>
                        </tbody>
                    </table>
                    <div class="alert-box" style="background:#f0f8ff;border-color:rgba(0,0,0,0.08);">
                        <div class="alert-icon">⚖️</div>
                        <div class="alert-text">
                            <strong>核心原则:</strong>只在你有权限的环境内操作。拿到认证(OSCE、BSCP)比非法操作更能体现技术价值。Bug Bounty 平台(HackerOne、SRC)提供了合法赚钱的渠道。
                        </div>
                    </div>
                    <div class="card-grid card-grid-3" style="gap:10px;">
                        <div class="info-card glass" style="padding:14px;">
                            <div style="font-size:20px;margin-bottom:6px;">🎓</div>
                            <div class="card-title" style="font-size:12px;">先从 CTF 开始</div>
                            <div class="card-desc">攻防世界、BUUCTF 有大量合法练习题,从 Easy 难度起步</div>
                        </div>
                        <div class="info-card glass" style="padding:14px;">
                            <div style="font-size:20px;margin-bottom:6px;">🏅</div>
                            <div class="card-title" style="font-size:12px;">参与 Bug Bounty</div>
                            <div class="card-desc">各大厂均有 SRC 漏洞奖励,报告漏洞合法且有收益</div>
                        </div>
                        <div class="info-card glass" style="padding:14px;">
                            <div style="font-size:20px;margin-bottom:6px;">📝</div>
                            <div class="card-title" style="font-size:12px;">签署授权协议</div>
                            <div class="card-desc">渗透测试前务必签书面授权,保护自己和委托方</div>
                        </div>
                    </div>
                </div>
                <div class="slide-footer">
                    <div class="footer-brand">ANDROID REVERSE</div>
                    <div class="footer-line"></div>
                    <div class="footer-page">09 / 10</div>
                </div>
            </div>
        </div>

        <!-- ======= SLIDE 10: 学习路线 ======= -->
        <div class="slide" id="slide-10">
            <div class="slide-content">
                <div class="section-header">
                    <div class="section-label">Chapter 09</div>
                    <div class="accent-line"></div>
                    <div class="section-title">从零到实战:学习路线图</div>
                </div>
                <div class="two-col" style="flex:1;gap:20px;">
                    <div>
                        <div class="timeline">
                            <div class="timeline-item">
                                <div class="timeline-dot active-dot">1</div>
                                <div class="timeline-content">
                                    <div class="timeline-title">第 1-2 周:基础准备</div>
                                    <div class="timeline-desc">学 Java 基础语法 → 了解 Android 开发结构 → 搭建 Android Studio 环境,写一个简单 APP</div>
                                </div>
                            </div>
                            <div class="timeline-item">
                                <div class="timeline-dot active-dot">2</div>
                                <div class="timeline-content">
                                    <div class="timeline-title">第 3-4 周:静态分析入门</div>
                                    <div class="timeline-desc">安装 jadx,解析开源 APK(如 GadgetBridge),读懂类结构和方法调用关系</div>
                                </div>
                            </div>
                            <div class="timeline-item">
                                <div class="timeline-dot active-dot">3</div>
                                <div class="timeline-content">
                                    <div class="timeline-title">第 5-6 周:Smali 与重打包</div>
                                    <div class="timeline-desc">用 apktool 解包 → 修改 Smali → 重打包签名 → 安装验证,完成第一次 patch</div>
                                </div>
                            </div>
                            <div class="timeline-item">
                                <div class="timeline-dot active-dot">4</div>
                                <div class="timeline-content">
                                    <div class="timeline-title">第 7-8 周:动态分析 Frida</div>
                                    <div class="timeline-desc">配置 Frida 环境 → 完成基本 hook → 追踪加密函数 → 打印调用栈定位逻辑</div>
                                </div>
                            </div>
                            <div class="timeline-item">
                                <div class="timeline-dot">5</div>
                                <div class="timeline-content">
                                    <div class="timeline-title">第 2-3 月:CTF 实战</div>
                                    <div class="timeline-desc">在 CTF 平台做 Android 题,解决真实混淆/加壳场景,积累解题经验</div>
                                </div>
                            </div>
                        </div>
                    </div>
                    <div style="display:flex;flex-direction:column;gap:12px;">
                        <div class="info-card glass">
                            <div class="card-title">🛠 推荐练习 APK</div>
                            <div style="margin-top:10px;display:flex;flex-direction:column;gap:6px;">
                                <div style="font-size:11px;color:#6e6e73;display:flex;justify-content:space-between;padding:6px 0;border-bottom:1px solid rgba(0,0,0,0.04);">
                                    <span style="font-weight:600;color:#1d1d1f;">InsecureBank v2</span>
                                    <span class="tag-pill">入门</span>
                                </div>
                                <div style="font-size:11px;color:#6e6e73;display:flex;justify-content:space-between;padding:6px 0;border-bottom:1px solid rgba(0,0,0,0.04);">
                                    <span style="font-weight:600;color:#1d1d1f;">DIVA Android</span>
                                    <span class="tag-pill">入门</span>
                                </div>
                                <div style="font-size:11px;color:#6e6e73;display:flex;justify-content:space-between;padding:6px 0;border-bottom:1px solid rgba(0,0,0,0.04);">
                                    <span style="font-weight:600;color:#1d1d1f;">UnCrackable Level 1-3</span>
                                    <span class="tag-pill">进阶</span>
                                </div>
                                <div style="font-size:11px;color:#6e6e73;display:flex;justify-content:space-between;padding:6px 0;">
                                    <span style="font-weight:600;color:#1d1d1f;">OWASP GoatDroid</span>
                                    <span class="tag-pill">综合</span>
                                </div>
                            </div>
                        </div>
                        <div class="info-card glass" style="flex:1;">
                            <div class="card-title">🎯 技能树总览</div>
                            <div style="margin-top:10px;display:grid;grid-template-columns:1fr 1fr;gap:6px;">
                                <div style="background:#f5f5f7;border-radius:6px;padding:6px 8px;font-size:10px;font-weight:600;color:#1d1d1f;">Java/Kotlin</div>
                                <div style="background:#f5f5f7;border-radius:6px;padding:6px 8px;font-size:10px;font-weight:600;color:#1d1d1f;">Smali 语法</div>
                                <div style="background:#f5f5f7;border-radius:6px;padding:6px 8px;font-size:10px;font-weight:600;color:#1d1d1f;">jadx 使用</div>
                                <div style="background:#f5f5f7;border-radius:6px;padding:6px 8px;font-size:10px;font-weight:600;color:#1d1d1f;">apktool 重打包</div>
                                <div style="background:#f5f5f7;border-radius:6px;padding:6px 8px;font-size:10px;font-weight:600;color:#1d1d1f;">Frida 插桩</div>
                                <div style="background:#f5f5f7;border-radius:6px;padding:6px 8px;font-size:10px;font-weight:600;color:#1d1d1f;">抓包分析</div>
                                <div style="background:#f5f5f7;border-radius:6px;padding:6px 8px;font-size:10px;font-weight:600;color:#6e6e73;">ARM 汇编</div>
                                <div style="background:#f5f5f7;border-radius:6px;padding:6px 8px;font-size:10px;font-weight:600;color:#6e6e73;">脱壳技术</div>
                            </div>
                            <div style="margin-top:8px;font-size:10px;color:#6e6e73;">灰色 = 高级阶段学习</div>
                        </div>
                    </div>
                </div>
                <div class="slide-footer">
                    <div class="footer-brand">ANDROID REVERSE</div>
                    <div class="footer-line"></div>
                    <div class="footer-page">10 / 10</div>
                </div>
            </div>
        </div>

    </div>

    <!-- 进度点 -->
    <div class="slide-progress" id="slideProgress"></div>
    <div class="keyboard-hint">使用 <span class="kbd">←</span> <span class="kbd">→</span> 方向键或点击缩略图切换幻灯片</div>
</div>

<script>
    // ============================================
    // 幻灯片数据
    // ============================================
    const slidesData = [
        { num: 1, title: '安卓逆向工程简介', subtitle: '入门指南' },
        { num: 2, title: '什么是逆向工程', subtitle: 'APK 结构与原理' },
        { num: 3, title: '必备工具全景', subtitle: 'jadx / Frida / apktool' },
        { num: 4, title: '标准分析流程', subtitle: '5步法' },
        { num: 5, title: 'Smali 语言', subtitle: '安卓汇编基础' },
        { num: 6, title: '6大保护机制', subtitle: '混淆/加壳/SSL Pinning' },
        { num: 7, title: 'Frida 动态分析', subtitle: '实战脚本' },
        { num: 8, title: '行业数据', subtitle: '现状与资源' },
        { num: 9, title: '法律与道德', subtitle: '合规边界' },
        { num: 10, title: '学习路线图', subtitle: '从零到实战' },
    ];

    const totalSlides = slidesData.length;
    let currentSlide = 1;

    // ============================================
    // 初始化缩略图
    // ============================================
    function initSidebar() {
        const sidebar = document.getElementById('sidebar');
        slidesData.forEach((data, index) => {
            const item = document.createElement('div');
            item.className = 'thumb-item' + (index === 0 ? ' active' : '');
            item.id = 'thumb-' + (index + 1);
            item.onclick = () => goToSlide(index + 1);
            item.innerHTML = `
                <div class="thumb-inner" style="background:${index === 0 ? '#fff' : '#f8f8f8'};">
                    <div class="thumb-title">${data.title}</div>
                    <div class="thumb-subtitle">${data.subtitle}</div>
                    <div class="thumb-num">${String(index + 1).padStart(2, '0')}</div>
                </div>
            `;
            sidebar.appendChild(item);
        });
    }

    // ============================================
    // 初始化进度点
    // ============================================
    function initProgress() {
        const container = document.getElementById('slideProgress');
        slidesData.forEach((_, index) => {
            const dot = document.createElement('div');
            dot.className = 'progress-dot' + (index === 0 ? ' active' : '');
            dot.id = 'dot-' + (index + 1);
            dot.onclick = () => goToSlide(index + 1);
            container.appendChild(dot);
        });
    }

    // ============================================
    // 切换幻灯片
    // ============================================
    function goToSlide(num) {
        if (num < 1 || num > totalSlides) return;

        // 隐藏当前
        document.getElementById('slide-' + currentSlide).classList.remove('active');
        document.getElementById('thumb-' + currentSlide).classList.remove('active');
        document.getElementById('dot-' + currentSlide).classList.remove('active');

        currentSlide = num;

        // 显示新的
        document.getElementById('slide-' + currentSlide).classList.add('active');
        document.getElementById('thumb-' + currentSlide).classList.add('active');
        document.getElementById('dot-' + currentSlide).classList.add('active');

        // 更新指示器
        document.getElementById('slideIndicator').textContent = `${currentSlide} / ${totalSlides}`;

        // 滚动缩略图到可见
        const thumb = document.getElementById('thumb-' + currentSlide);
        thumb.scrollIntoView({ behavior: 'smooth', block: 'nearest' });
    }

    function nextSlide() { goToSlide(currentSlide + 1); }
    function prevSlide() { goToSlide(currentSlide - 1); }

    // 键盘事件
    document.addEventListener('keydown', (e) => {
        if (e.key === 'ArrowRight' || e.key === 'ArrowDown') nextSlide();
        if (e.key === 'ArrowLeft' || e.key === 'ArrowUp') prevSlide();
    });

    // ============================================
    // 导出 PPTX
    // ============================================
    async function exportPPTX() {
        const loading = document.getElementById('exportLoading');
        loading.classList.remove('hidden');

        try {
            // 动态加载 pptxgenjs
            await loadScript('https://unpkg.com/pptxgenjs@4.0.1/dist/pptxgen.bundle.js');

            const pptx = new PptxGenJS();

            // 幻灯片尺寸 16:9
            pptx.layout = 'LAYOUT_WIDE';
            pptx.author = 'Android Reverse Engineering';
            pptx.company = 'Security Research';
            pptx.subject = '安卓逆向工程简介';
            pptx.title = '安卓逆向工程简介';

            // 定义主题色
            const C = {
                black: '1d1d1f',
                gray: '6e6e73',
                lightGray: 'f5f5f7',
                border: 'd2d2d7',
                white: 'ffffff',
                bgLight: 'fafafa',
            };

            // ──────────────────────────────
            // SLIDE 1: 封面
            // ──────────────────────────────
            {
                const slide = pptx.addSlide();
                slide.background = { color: C.white };

                // 左侧装饰块
                slide.addShape(pptx.ShapeType.rect, {
                    x: 0, y: 0, w: 0.06, h: 7.5,
                    fill: { color: C.black }
                });

                // 标签
                slide.addText('🔍  技术入门指南 · 2024', {
                    x: 0.5, y: 1.0, w: 5, h: 0.35,
                    fontSize: 10, color: C.gray, bold: true,
                    fontFace: 'Arial'
                });

                // 主标题
                slide.addText('安卓逆向工程简介', {
                    x: 0.5, y: 1.5, w: 6.5, h: 1.4,
                    fontSize: 46, color: C.black, bold: true,
                    fontFace: 'Arial', charSpacing: -1
                });

                // 副标题
                slide.addText('了解 Android APK 如何被分析、解构与研究\n从工具到流程,系统性入门指南', {
                    x: 0.5, y: 3.1, w: 5.5, h: 0.9,
                    fontSize: 14, color: C.gray,
                    fontFace: 'Arial', lineSpacingMultiple: 1.4
                });

                // 分割线
                slide.addShape(pptx.ShapeType.line, {
                    x: 0.5, y: 4.2, w: 5.5, h: 0,
                    line: { color: C.border, width: 1 }
                });

                // Meta 信息
                slide.addText('🎯 适合初学者  ·  📱 Android 平台  ·  ⏱ 预计阅读 15 分钟', {
                    x: 0.5, y: 4.35, w: 6, h: 0.3,
                    fontSize: 10, color: C.gray, fontFace: 'Arial'
                });

                // 右侧代码卡片背景
                slide.addShape(pptx.ShapeType.roundRect, {
                    x: 7.2, y: 1.2, w: 5.5, h: 3.8,
                    fill: { color: C.lightGray },
                    line: { color: 'e0e0e5', width: 1 },
                    rectRadius: 0.15
                });

                slide.addText('📄  APK 结构示意', {
                    x: 7.5, y: 1.45, w: 4.5, h: 0.3,
                    fontSize: 11, color: C.black, bold: true, fontFace: 'Courier New'
                });

                const codeLines = [
                    '# APK 本质是 ZIP 压缩文件',
                    'app.apk/',
                    '├── classes.dex    # 代码(逆向目标)',
                    '├── res/           # 图片/布局资源',
                    '├── lib/           # Native SO 库',
                    '├── assets/        # 原始资源文件',
                    '└── AndroidManifest.xml',
                ];

                codeLines.forEach((line, i) => {
                    slide.addText(line, {
                        x: 7.5, y: 1.9 + i * 0.3, w: 4.8, h: 0.28,
                        fontSize: 10, color: line.startsWith('#') ? C.gray : C.black,
                        fontFace: 'Courier New', bold: line.includes('classes.dex')
                    });
                });

                // 页脚
                slide.addText('ANDROID REVERSE ENGINEERING', {
                    x: 0.5, y: 7.0, w: 5, h: 0.25,
                    fontSize: 8, color: C.border, bold: true, fontFace: 'Arial'
                });
                slide.addText('01 / 10', {
                    x: 11.5, y: 7.0, w: 1.2, h: 0.25,
                    fontSize: 8, color: C.border, fontFace: 'Arial', align: 'right'
                });
            }

            // ──────────────────────────────
            // SLIDE 2: 什么是逆向工程
            // ──────────────────────────────
            {
                const slide = pptx.addSlide();
                slide.background = { color: C.white };

                slide.addShape(pptx.ShapeType.rect, {
                    x: 0, y: 0, w: 0.06, h: 7.5,
                    fill: { color: C.black }
                });

                // 章节标签
                slide.addText('CHAPTER 01', {
                    x: 0.5, y: 0.5, w: 4, h: 0.25,
                    fontSize: 9, color: C.gray, bold: true, fontFace: 'Arial', charSpacing: 1
                });

                // 装饰线
                slide.addShape(pptx.ShapeType.rect, {
                    x: 0.5, y: 0.82, w: 0.5, h: 0.04,
                    fill: { color: C.black }
                });

                slide.addText('什么是安卓逆向工程?', {
                    x: 0.5, y: 0.95, w: 11, h: 0.7,
                    fontSize: 28, color: C.black, bold: true, fontFace: 'Arial', charSpacing: -0.5
                });

                // 左列:通俗理解卡片
                slide.addShape(pptx.ShapeType.roundRect, {
                    x: 0.5, y: 1.85, w: 5.8, h: 1.7,
                    fill: { color: C.lightGray }, line: { color: 'e8e8ed', width: 1 },
                    rectRadius: 0.12
                });
                slide.addText('🔧 通俗理解', {
                    x: 0.75, y: 1.98, w: 5, h: 0.3,
                    fontSize: 12, color: C.black, bold: true, fontFace: 'Arial'
                });
                slide.addText('你下载了一个 APP,但没有源代码。逆向工程就是把这个 APP 的 classes.dex(编译后的代码文件)还原回你能读懂的 Java 代码,就像把熟食还原成菜谱。', {
                    x: 0.75, y: 2.32, w: 5.3, h: 1.0,
                    fontSize: 11, color: C.gray, fontFace: 'Arial', lineSpacingMultiple: 1.3
                });

                // 左列:合法场景卡片
                slide.addShape(pptx.ShapeType.roundRect, {
                    x: 0.5, y: 3.7, w: 5.8, h: 2.5,
                    fill: { color: C.lightGray }, line: { color: 'e8e8ed', width: 1 },
                    rectRadius: 0.12
                });
                slide.addText('⚖️ 合法应用场景', {
                    x: 0.75, y: 3.83, w: 5, h: 0.3,
                    fontSize: 12, color: C.black, bold: true, fontFace: 'Arial'
                });
                const legalCases = [
                    '• 安全研究:发现 APP 漏洞并向厂商上报',
                    '• 恶意软件分析:分析病毒/木马行为',
                    '• 协议还原:分析 APP 通信协议',
                    '• 自己的代码:忘记源码时恢复逻辑',
                ];
                legalCases.forEach((text, i) => {
                    slide.addText(text, {
                        x: 0.75, y: 4.18 + i * 0.45, w: 5.3, h: 0.38,
                        fontSize: 11, color: C.gray, fontFace: 'Arial'
                    });
                });

                // 右列:编译链
                slide.addShape(pptx.ShapeType.roundRect, {
                    x: 6.7, y: 1.85, w: 5.8, h: 4.35,
                    fill: { color: C.lightGray }, line: { color: 'e8e8ed', width: 1 },
                    rectRadius: 0.12
                });
                slide.addText('📦 Android 代码编译链', {
                    x: 6.95, y: 1.98, w: 5, h: 0.3,
                    fontSize: 12, color: C.black, bold: true, fontFace: 'Arial'
                });

                const chain = [
                    { title: '.java / .kt 源码', desc: '开发者编写的代码', dark: false },
                    { title: '↓ javac / kotlinc 编译', desc: '', dark: false, arrow: true },
                    { title: '.class 字节码', desc: 'JVM 字节码格式', dark: false },
                    { title: '↓ d8 / dx 工具转换', desc: '', dark: false, arrow: true },
                    { title: 'classes.dex', desc: 'Dalvik 字节码 — 逆向分析的目标', dark: true },
                ];

                let yPos = 2.35;
                chain.forEach(item => {
                    if (item.arrow) {
                        slide.addText(item.title, {
                            x: 6.95, y: yPos, w: 5.3, h: 0.3,
                            fontSize: 10, color: C.gray, fontFace: 'Arial', align: 'center'
                        });
                        yPos += 0.32;
                    } else {
                        slide.addShape(pptx.ShapeType.roundRect, {
                            x: 6.95, y: yPos, w: 5.3, h: 0.65,
                            fill: { color: item.dark ? C.black : C.white },
                            line: { color: item.dark ? C.black : 'e0e0e5', width: 1 },
                            rectRadius: 0.08
                        });
                        slide.addText(item.title, {
                            x: 7.1, y: yPos + 0.08, w: 5, h: 0.28,
                            fontSize: 12, color: item.dark ? C.white : C.black,
                            bold: true, fontFace: 'Arial'
                        });
                        if (item.desc) {
                            slide.addText(item.desc, {
                                x: 7.1, y: yPos + 0.35, w: 5, h: 0.22,
                                fontSize: 9, color: item.dark ? 'aaaaaa' : C.gray, fontFace: 'Arial'
                            });
                        }
                        yPos += 0.72;
                    }
                });

                slide.addText('ANDROID REVERSE ENGINEERING', {
                    x: 0.5, y: 7.0, w: 5, h: 0.25,
                    fontSize: 8, color: C.border, bold: true, fontFace: 'Arial'
                });
                slide.addText('02 / 10', {
                    x: 11.5, y: 7.0, w: 1.2, h: 0.25,
                    fontSize: 8, color: C.border, fontFace: 'Arial', align: 'right'
                });
            }

            // ──────────────────────────────
            // SLIDE 3: 核心工具
            // ──────────────────────────────
            {
                const slide = pptx.addSlide();
                slide.background = { color: C.white };

                slide.addShape(pptx.ShapeType.rect, {
                    x: 0, y: 0, w: 0.06, h: 7.5,
                    fill: { color: C.black }
                });
                slide.addText('CHAPTER 02', {
                    x: 0.5, y: 0.5, w: 4, h: 0.25,
                    fontSize: 9, color: C.gray, bold: true, fontFace: 'Arial', charSpacing: 1
                });
                slide.addShape(pptx.ShapeType.rect, {
                    x: 0.5, y: 0.82, w: 0.5, h: 0.04,
                    fill: { color: C.black }
                });
                slide.addText('必备逆向工具全景', {
                    x: 0.5, y: 0.95, w: 11, h: 0.7,
                    fontSize: 28, color: C.black, bold: true, fontFace: 'Arial'
                });

                const tools = [
                    { icon: '🔓', name: 'jadx', tag: '反编译', desc: '把 APK/dex 直接反编译成可读的 Java 代码,带 GUI 界面,新手首选工具,支持搜索、交叉引用等功能' },
                    { icon: '🔨', name: 'apktool v2.9.3', tag: '重打包', desc: '解包 APK → 修改 Smali 代码 → 重新打包。适合需要修改代码后重新安装的场景' },
                    { icon: '🕵️', name: 'Frida 16.x', tag: '动态分析', desc: '动态插桩框架,用 JavaScript 脚本在运行中 hook 任意函数,实时修改参数和返回值' },
                    { icon: '🌐', name: 'Charles / mitmproxy', tag: '流量分析', desc: '抓取 APP 的 HTTPS 网络请求,查看 APP 发送的数据、API 接口格式与参数结构' },
                    { icon: '🏗️', name: 'IDA Pro / Ghidra', tag: 'Native 分析', desc: '分析 .so 原生库(C/C++ 编译的 ARM 代码),Ghidra 免费开源,NSA 出品,功能完备' },
                ];

                tools.forEach((tool, i) => {
                    const y = 1.9 + i * 1.02;
                    slide.addShape(pptx.ShapeType.roundRect, {
                        x: 0.5, y, w: 12.2, h: 0.88,
                        fill: { color: C.lightGray }, line: { color: 'e8e8ed', width: 1 },
                        rectRadius: 0.1
                    });
                    slide.addText(tool.icon, {
                        x: 0.65, y: y + 0.22, w: 0.5, h: 0.45,
                        fontSize: 20, fontFace: 'Arial'
                    });
                    slide.addText(tool.name, {
                        x: 1.3, y: y + 0.12, w: 3, h: 0.3,
                        fontSize: 13, color: C.black, bold: true, fontFace: 'Arial'
                    });
                    slide.addText(tool.desc, {
                        x: 1.3, y: y + 0.45, w: 9.3, h: 0.28,
                        fontSize: 10, color: C.gray, fontFace: 'Arial'
                    });
                    // 标签
                    slide.addShape(pptx.ShapeType.roundRect, {
                        x: 11.1, y: y + 0.22, w: 1.3, h: 0.32,
                        fill: { color: 'ebebf0' }, line: { color: 'e0e0e5', width: 1 },
                        rectRadius: 0.04
                    });
                    slide.addText(tool.tag, {
                        x: 11.1, y: y + 0.24, w: 1.3, h: 0.28,
                        fontSize: 9, color: C.gray, bold: true, fontFace: 'Arial', align: 'center'
                    });
                });

                slide.addText('ANDROID REVERSE ENGINEERING', {
                    x: 0.5, y: 7.0, w: 5, h: 0.25,
                    fontSize: 8, color: C.border, bold: true, fontFace: 'Arial'
                });
                slide.addText('03 / 10', {
                    x: 11.5, y: 7.0, w: 1.2, h: 0.25,
                    fontSize: 8, color: C.border, fontFace: 'Arial', align: 'right'
                });
            }

            // ──────────────────────────────
            // SLIDE 4: 逆向工作流
            // ──────────────────────────────
            {
                const slide = pptx.addSlide();
                slide.background = { color: C.white };

                slide.addShape(pptx.ShapeType.rect, {
                    x: 0, y: 0, w: 0.06, h: 7.5,
                    fill: { color: C.black }
                });
                slide.addText('CHAPTER 03', {
                    x: 0.5, y: 0.5, w: 4, h: 0.25,
                    fontSize: 9, color: C.gray, bold: true, fontFace: 'Arial', charSpacing: 1
                });
                slide.addShape(pptx.ShapeType.rect, {
                    x: 0.5, y: 0.82, w: 0.5, h: 0.04,
                    fill: { color: C.black }
                });
                slide.addText('标准逆向分析流程', {
                    x: 0.5, y: 0.95, w: 11, h: 0.7,
                    fontSize: 28, color: C.black, bold: true, fontFace: 'Arial'
                });

                // 流程步骤
                const steps = [
                    { num: '1', title: '获取 APK', desc: 'adb pull 或\nAPKPure 下载' },
                    { num: '2', title: '静态分析', desc: 'jadx 查看代码\n结构与权限' },
                    { num: '3', title: '定位目标', desc: '搜索 login/check\n/encrypt 等关键词' },
                    { num: '4', title: '动态验证', desc: 'Frida hook\n打印参数返回值' },
                    { num: '5', title: '整理结论', desc: '记录逻辑接口\n和加密算法' },
                ];

                steps.forEach((step, i) => {
                    const x = 0.5 + i * 2.42;
                    // 圆圈
                    slide.addShape(pptx.ShapeType.ellipse, {
                        x: x + 0.7, y: 1.95, w: 0.8, h: 0.8,
                        fill: { color: C.black }
                    });
                    slide.addText(step.num, {
                        x: x + 0.7, y: 1.97, w: 0.8, h: 0.76,
                        fontSize: 14, color: C.white, bold: true,
                        fontFace: 'Arial', align: 'center', valign: 'middle'
                    });
                    // 连接线
                    if (i < 4) {
                        slide.addShape(pptx.ShapeType.line, {
                            x: x + 1.52, y: 2.35, w: 0.88, h: 0,
                            line: { color: C.border, width: 1 }
                        });
                    }
                    slide.addText(step.title, {
                        x, y: 2.88, w: 2.2, h: 0.3,
                        fontSize: 11, color: C.black, bold: true,
                        fontFace: 'Arial', align: 'center'
                    });
                    slide.addText(step.desc, {
                        x, y: 3.2, w: 2.2, h: 0.5,
                        fontSize: 9, color: C.gray,
                        fontFace: 'Arial', align: 'center', lineSpacingMultiple: 1.3
                    });
                });

                // 底部三列代码/提示
                const cols = [
                    {
                        title: '🔍 常用 adb 命令',
                        lines: ['# 列出所有已安装包名', 'adb shell pm list packages', '', '# 提取 APK 文件', 'adb pull \\', '  /data/app/xxx/base.apk .']
                    },
                    {
                        title: '🪝 Frida Hook 模板',
                        lines: ['Java.perform(function() {', '  var Cls = Java.use(', '    "com.app.Login");', '  Cls.check.implementation', '    = function() {', '    return true; // 绕过', '  };', '});']
                    },
                    {
                        title: '📋 静态分析清单',
                        lines: ['☑ AndroidManifest 权限声明', '☑ 网络请求域名和接口', '☑ 本地 SharedPrefs 存储', '☑ 加密算法调用位置', '☑ 混淆程度和命名规则', '☑ 第三方 SDK 引入情况']
                    },
                ];

                cols.forEach((col, i) => {
                    const x = 0.5 + i * 4.1;
                    slide.addShape(pptx.ShapeType.roundRect, {
                        x, y: 3.9, w: 3.85, h: 2.7,
                        fill: { color: C.lightGray }, line: { color: 'e8e8ed', width: 1 },
                        rectRadius: 0.1
                    });
                    slide.addText(col.title, {
                        x: x + 0.15, y: 4.03, w: 3.55, h: 0.28,
                        fontSize: 11, color: C.black, bold: true, fontFace: 'Arial'
                    });
                    col.lines.forEach((line, j) => {
                        slide.addText(line, {
                            x: x + 0.15, y: 4.38 + j * 0.33, w: 3.55, h: 0.28,
                            fontSize: 9,
                            color: line.startsWith('#') || line.startsWith('') ? C.gray : C.black,
                            fontFace: line.startsWith('') ? 'Arial' : 'Courier New'
                        });
                    });
                });

                slide.addText('ANDROID REVERSE ENGINEERING', {
                    x: 0.5, y: 7.0, w: 5, h: 0.25,
                    fontSize: 8, color: C.border, bold: true, fontFace: 'Arial'
                });
                slide.addText('04 / 10', {
                    x: 11.5, y: 7.0, w: 1.2, h: 0.25,
                    fontSize: 8, color: C.border, fontFace: 'Arial', align: 'right'
                });
            }

            // ──────────────────────────────
            // SLIDE 5: Smali
            // ──────────────────────────────
            {
                const slide = pptx.addSlide();
                slide.background = { color: C.white };

                slide.addShape(pptx.ShapeType.rect, {
                    x: 0, y: 0, w: 0.06, h: 7.5,
                    fill: { color: C.black }
                });
                slide.addText('CHAPTER 04', {
                    x: 0.5, y: 0.5, w: 4, h: 0.25,
                    fontSize: 9, color: C.gray, bold: true, fontFace: 'Arial', charSpacing: 1
                });
                slide.addShape(pptx.ShapeType.rect, {
                    x: 0.5, y: 0.82, w: 0.5, h: 0.04,
                    fill: { color: C.black }
                });
                slide.addText('读懂 Smali —— 安卓汇编语言', {
                    x: 0.5, y: 0.95, w: 12, h: 0.7,
                    fontSize: 28, color: C.black, bold: true, fontFace: 'Arial'
                });

                // 左:Java 代码
                slide.addText('原始 Java 代码', {
                    x: 0.5, y: 1.85, w: 5.5, h: 0.28,
                    fontSize: 11, color: C.gray, bold: true, fontFace: 'Arial'
                });
                slide.addShape(pptx.ShapeType.roundRect, {
                    x: 0.5, y: 2.15, w: 5.5, h: 2.4,
                    fill: { color: C.lightGray }, line: { color: 'e8e8ed', width: 1 },
                    rectRadius: 0.1
                });
                const javaCode = [
                    'public boolean isVip(String uid) {',
                    '  if (uid.equals("admin")) {',
                    '    return true;',
                    '  }',
                    '  return false;',
                    '}',
                ];
                javaCode.forEach((line, i) => {
                    slide.addText(line, {
                        x: 0.7, y: 2.28 + i * 0.34, w: 5.1, h: 0.3,
                        fontSize: 11, color: C.black, fontFace: 'Courier New'
                    });
                });

                // 寄存器规则
                slide.addText('关键寄存器规则', {
                    x: 0.5, y: 4.7, w: 5.5, h: 0.28,
                    fontSize: 11, color: C.gray, bold: true, fontFace: 'Arial'
                });
                const regs = [
                    { reg: 'v0', desc: '本地变量寄存器,从 v0 开始编号' },
                    { reg: 'p0', desc: '参数寄存器,p0 = this(实例方法)' },
                    { reg: 'p1', desc: '第一个参数,此例中 p1 = uid' },
                ];
                regs.forEach((r, i) => {
                    slide.addShape(pptx.ShapeType.roundRect, {
                        x: 0.5, y: 5.02 + i * 0.52, w: 5.5, h: 0.42,
                        fill: { color: C.lightGray }, line: { color: 'e8e8ed', width: 1 },
                        rectRadius: 0.06
                    });
                    slide.addText(r.reg, {
                        x: 0.65, y: 5.05 + i * 0.52, w: 0.5, h: 0.36,
                        fontSize: 12, color: C.black, bold: true, fontFace: 'Courier New'
                    });
                    slide.addText(r.desc, {
                        x: 1.3, y: 5.07 + i * 0.52, w: 4.5, h: 0.32,
                        fontSize: 10, color: C.gray, fontFace: 'Arial'
                    });
                });

                // 右:Smali 代码
                slide.addText('对应 Smali 代码(逆向后看到的)', {
                    x: 6.5, y: 1.85, w: 6.2, h: 0.28,
                    fontSize: 11, color: C.gray, bold: true, fontFace: 'Arial'
                });
                slide.addShape(pptx.ShapeType.roundRect, {
                    x: 6.5, y: 2.15, w: 6.2, h: 3.5,
                    fill: { color: C.lightGray }, line: { color: 'e8e8ed', width: 1 },
                    rectRadius: 0.1
                });
                const smaliCode = [
                    '.method public isVip(Ljava/lang/String;)Z',
                    '  .registers 3   # v0, p0(this), p1(uid)',
                    '',
                    '  const-string v0, "admin"',
                    '  invoke-virtual {p1, v0},',
                    '    Ljava/lang/String;->equals(Ljava/lang/Object;)Z',
                    '  move-result v0',
                    '  if-eqz v0, :cond_0   # 若不等则跳转',
                    '',
                    '  const/4 v0, 0x1      # true',
                    '  return v0',
                    '',
                    '  :cond_0',
                    '  const/4 v0, 0x0      # false',
                    '  return v0',
                    '.end method',
                ];
                smaliCode.forEach((line, i) => {
                    slide.addText(line, {
                        x: 6.65, y: 2.28 + i * 0.195, w: 5.9, h: 0.19,
                        fontSize: 9,
                        color: line.includes('#') ? C.gray : C.black,
                        fontFace: 'Courier New'
                    });
                });

                // 提示
                slide.addShape(pptx.ShapeType.roundRect, {
                    x: 6.5, y: 5.78, w: 6.2, h: 0.75,
                    fill: { color: 'fff8e1' }, line: { color: 'ffe082', width: 1 },
                    rectRadius: 0.08
                });
                slide.addText('💡  逆向修改技巧:将 if-eqz 改成 if-nez,或直接将 const/4 v0, 0x0 改成 0x1,即可绕过 isVip 验证,让所有用户都返回 true。', {
                    x: 6.65, y: 5.85, w: 5.9, h: 0.6,
                    fontSize: 10, color: '795548', fontFace: 'Arial', lineSpacingMultiple: 1.3
                });

                slide.addText('ANDROID REVERSE ENGINEERING', {
                    x: 0.5, y: 7.0, w: 5, h: 0.25,
                    fontSize: 8, color: C.border, bold: true, fontFace: 'Arial'
                });
                slide.addText('05 / 10', {
                    x: 11.5, y: 7.0, w: 1.2, h: 0.25,
                    fontSize: 8, color: C.border, fontFace: 'Arial', align: 'right'
                });
            }

            // ──────────────────────────────
            // SLIDE 6: 保护机制
            // ──────────────────────────────
            {
                const slide = pptx.addSlide();
                slide.background = { color: C.white };

                slide.addShape(pptx.ShapeType.rect, {
                    x: 0, y: 0, w: 0.06, h: 7.5,
                    fill: { color: C.black }
                });
                slide.addText('CHAPTER 05', {
                    x: 0.5, y: 0.5, w: 4, h: 0.25,
                    fontSize: 9, color: C.gray, bold: true, fontFace: 'Arial', charSpacing: 1
                });
                slide.addShape(pptx.ShapeType.rect, {
                    x: 0.5, y: 0.82, w: 0.5, h: 0.04,
                    fill: { color: C.black }
                });
                slide.addText('APP 的 6 大保护机制', {
                    x: 0.5, y: 0.95, w: 12, h: 0.7,
                    fontSize: 28, color: C.black, bold: true, fontFace: 'Arial'
                });

                const protections = [
                    { icon: '🌫️', title: '代码混淆 (ProGuard)', desc: '把 LoginActivity 改成 a.b.c,增加阅读难度,但逻辑不变,jadx 仍可反编译读取' },
                    { icon: '📦', title: '加壳 (Packing)', desc: '把真正的 dex 加密后隐藏,运行时再解密。常见:梆梆、360加固、腾讯乐固,需先脱壳' },
                    { icon: '🔐', title: 'SSL Pinning', desc: 'APP 内置证书指纹,只接受特定证书,阻止抓包。可用 Frida 脚本或 TrustMeAlready 绕过' },
                    { icon: '🔍', title: 'Root / 调试检测', desc: '检测 /system/bin/su 是否存在。可用 Magisk DenyList、RootBeer 模块进行对抗' },
                    { icon: '', title: 'VMP 虚拟机保护', desc: '核心算法被自定义虚拟机解释执行,指令集完全私有,是目前最难逆向的保护方式' },
                    { icon: '', title: '签名校验', desc: '运行时校验自身签名,重打包后签名变化会闪退。需 hook getSignatures() 返回原始签名' },
                ];

                protections.forEach((item, i) => {
                    const col = i % 3;
                    const row = Math.floor(i / 3);
                    const x = 0.5 + col * 4.1;
                    const y = 2.0 + row * 2.4;
                    slide.addShape(pptx.ShapeType.roundRect, {
                        x, y, w: 3.85, h: 2.1,
                        fill: { color: C.lightGray }, line: { color: 'e8e8ed', width: 1 },
                        rectRadius: 0.12
                    });
                    slide.addText(item.icon, {
                        x: x + 0.15, y: y + 0.18, w: 0.5, h: 0.5,
                        fontSize: 22, fontFace: 'Arial'
                    });
                    slide.addText(item.title, {
                        x: x + 0.15, y: y + 0.72, w: 3.5, h: 0.32,
                        fontSize: 12, color: C.black, bold: true, fontFace: 'Arial'
                    });
                    slide.addText(item.desc, {
                        x: x + 0.15, y: y + 1.08, w: 3.55, h: 0.85,
                        fontSize: 10, color: C.gray, fontFace: 'Arial', lineSpacingMultiple: 1.3
                    });
                });

                slide.addText('ANDROID REVERSE ENGINEERING', {
                    x: 0.5, y: 7.0, w: 5, h: 0.25,
                    fontSize: 8, color: C.border, bold: true, fontFace: 'Arial'
                });
                slide.addText('06 / 10', {
                    x: 11.5, y: 7.0, w: 1.2, h: 0.25,
                    fontSize: 8, color: C.border, fontFace: 'Arial', align: 'right'
                });
            }

            // ──────────────────────────────
            // SLIDE 7: Frida 动态分析
            // ──────────────────────────────
            {
                const slide = pptx.addSlide();
                slide.background = { color: C.white };

                slide.addShape(pptx.ShapeType.rect, {
                    x: 0, y: 0, w: 0.06, h: 7.5,
                    fill: { color: C.black }
                });
                slide.addText('CHAPTER 06', {
                    x: 0.5, y: 0.5, w: 4, h: 0.25,
                    fontSize: 9, color: C.gray, bold: true, fontFace: 'Arial', charSpacing: 1
                });
                slide.addShape(pptx.ShapeType.rect, {
                    x: 0.5, y: 0.82, w: 0.5, h: 0.04,
                    fill: { color: C.black }
                });
                slide.addText('Frida 动态分析实战', {
                    x: 0.5, y: 0.95, w: 12, h: 0.7,
                    fontSize: 28, color: C.black, bold: true, fontFace: 'Arial'
                });

                // 左侧:环境搭建
                slide.addText('① 环境搭建', {
                    x: 0.5, y: 1.85, w: 5.8, h: 0.28,
                    fontSize: 12, color: C.black, bold: true, fontFace: 'Arial'
                });
                slide.addShape(pptx.ShapeType.roundRect, {
                    x: 0.5, y: 2.15, w: 5.8, h: 2.2,
                    fill: { color: C.lightGray }, line: { color: 'e8e8ed', width: 1 },
                    rectRadius: 0.1
                });
                const setupCode = [
                    '# 安装 frida 命令行工具',
                    'pip install frida-tools',
                    '',
                    '# 推送 frida-server 到手机',
                    'adb push frida-server /data/local/tmp/',
                    'adb shell "chmod 755 /data/local/tmp/frida-server"',
                    'adb shell "/data/local/tmp/frida-server &"',
                ];
                setupCode.forEach((line, i) => {
                    slide.addText(line, {
                        x: 0.7, y: 2.28 + i * 0.27, w: 5.4, h: 0.24,
                        fontSize: 9.5, color: line.startsWith('#') ? C.gray : C.black,
                        fontFace: 'Courier New'
                    });
                });

                // 注入命令
                slide.addText('② 注入脚本到目标 APP', {
                    x: 0.5, y: 4.5, w: 5.8, h: 0.28,
                    fontSize: 12, color: C.black, bold: true, fontFace: 'Arial'
                });
                slide.addShape(pptx.ShapeType.roundRect, {
                    x: 0.5, y: 4.82, w: 5.8, h: 1.0,
                    fill: { color: C.lightGray }, line: { color: 'e8e8ed', width: 1 },
                    rectRadius: 0.1
                });
                const injectCode = [
                    '# 对目标包名注入脚本并启动',
                    'frida -U -f com.target.app \\',
                    '  -l hook.js --no-pause',
                ];
                injectCode.forEach((line, i) => {
                    slide.addText(line, {
                        x: 0.7, y: 4.95 + i * 0.27, w: 5.4, h: 0.24,
                        fontSize: 9.5, color: line.startsWith('#') ? C.gray : C.black,
                        fontFace: 'Courier New'
                    });
                });

                // 右侧:Hook 脚本
                slide.addText('③ Hook 实战脚本:追踪 MessageDigest 加密输入', {
                    x: 6.7, y: 1.85, w: 6, h: 0.28,
                    fontSize: 12, color: C.black, bold: true, fontFace: 'Arial'
                });
                slide.addShape(pptx.ShapeType.roundRect, {
                    x: 6.7, y: 2.15, w: 5.8, h: 3.65,
                    fill: { color: C.lightGray }, line: { color: 'e8e8ed', width: 1 },
                    rectRadius: 0.1
                });
                const hookCode = [
                    'Java.perform(function() {',
                    '  // Hook MessageDigest (MD5/SHA)',
                    '  var MD = Java.use(',
                    '    "java.security.MessageDigest");',
                    '',
                    '  MD.update.overload("[B")',
                    '    .implementation = function(b) {',
                    '    // 打印传入的原文数据',
                    '    var str = Java.use("java.lang.String").$new(b);',
                    '    console.log("[*] MD input: " + str);',
                    '',
                    '    // 打印调用栈,定位代码位置',
                    '    console.log(Java.use("android.util.Log")',
                    '      .getStackTraceString(',
                    '        Java.use("java.lang.Exception").$new()));',
                    '',
                    '    return this.update(b);  // 继续执行原函数',
                    '  };',
                    '});',
                ];
                hookCode.forEach((line, i) => {
                    slide.addText(line, {
                        x: 6.85, y: 2.28 + i * 0.175, w: 5.5, h: 0.17,
                        fontSize: 8.5,
                        color: line.includes('//') ? C.gray : C.black,
                        fontFace: 'Courier New'
                    });
                });

                slide.addText('ANDROID REVERSE ENGINEERING', {
                    x: 0.5, y: 7.0, w: 5, h: 0.25,
                    fontSize: 8, color: C.border, bold: true, fontFace: 'Arial'
                });
                slide.addText('07 / 10', {
                    x: 11.5, y: 7.0, w: 1.2, h: 0.25,
                    fontSize: 8, color: C.border, fontFace: 'Arial', align: 'right'
                });
            }

            // ──────────────────────────────
            // SLIDE 8: 行业数据
            // ──────────────────────────────
            {
                const slide = pptx.addSlide();
                slide.background = { color: C.white };

                slide.addShape(pptx.ShapeType.rect, {
                    x: 0, y: 0, w: 0.06, h: 7.5,
                    fill: { color: C.black }
                });
                slide.addText('CHAPTER 07', {
                    x: 0.5, y: 0.5, w: 4, h: 0.25,
                    fontSize: 9, color: C.gray, bold: true, fontFace: 'Arial', charSpacing: 1
                });
                slide.addShape(pptx.ShapeType.rect, {
                    x: 0.5, y: 0.82, w: 0.5, h: 0.04,
                    fill: { color: C.black }
                });
                slide.addText('行业数据与应用现状', {
                    x: 0.5, y: 0.95, w: 12, h: 0.7,
                    fontSize: 28, color: C.black, bold: true, fontFace: 'Arial'
                });

                // 三个统计数字
                const stats = [
                    { num: '35%', label: 'Google Play APP\n使用了代码混淆', src: 'NowSecure 2023' },
                    { num: '73%', label: '金融类 APP 存在\n高危安全漏洞', src: 'OWASP Mobile Top 10' },
                    { num: '$38K', label: 'Google 安卓漏洞\n最高 Bug Bounty 奖励', src: 'Google VRP 2023' },
                ];
                stats.forEach((s, i) => {
                    const x = 0.5 + i * 4.1;
                    slide.addShape(pptx.ShapeType.roundRect, {
                        x, y: 1.95, w: 3.85, h: 1.7,
                        fill: { color: C.lightGray }, line: { color: 'e8e8ed', width: 1 },
                        rectRadius: 0.12
                    });
                    slide.addText(s.num, {
                        x, y: 2.05, w: 3.85, h: 0.75,
                        fontSize: 36, color: C.black, bold: true,
                        fontFace: 'Arial', align: 'center', charSpacing: -1
                    });
                    slide.addText(s.label, {
                        x, y: 2.82, w: 3.85, h: 0.45,
                        fontSize: 10, color: C.gray,
                        fontFace: 'Arial', align: 'center', lineSpacingMultiple: 1.3
                    });
                    slide.addText(s.src, {
                        x, y: 3.3, w: 3.85, h: 0.25,
                        fontSize: 8, color: C.border,
                        fontFace: 'Arial', align: 'center'
                    });
                });

                // 应用场景条形图
                slide.addShape(pptx.ShapeType.roundRect, {
                    x: 0.5, y: 3.9, w: 5.8, h: 2.65,
                    fill: { color: C.lightGray }, line: { color: 'e8e8ed', width: 1 },
                    rectRadius: 0.12
                });
                slide.addText('📊 逆向工程主要应用场景', {
                    x: 0.7, y: 4.03, w: 5.3, h: 0.28,
                    fontSize: 12, color: C.black, bold: true, fontFace: 'Arial'
                });
                const bars = [
                    { label: '安全漏洞研究', pct: 45 },
                    { label: '恶意软件分析', pct: 30 },
                    { label: '协议还原分析', pct: 15 },
                    { label: '其他(兼容/测试)', pct: 10 },
                ];
                bars.forEach((bar, i) => {
                    const y = 4.45 + i * 0.52;
                    slide.addText(bar.label, {
                        x: 0.7, y, w: 2.5, h: 0.25,
                        fontSize: 10, color: C.black, fontFace: 'Arial', bold: true
                    });
                    slide.addText(`${bar.pct}%`, {
                        x: 5.6, y, w: 0.5, h: 0.25,
                        fontSize: 10, color: C.gray, fontFace: 'Arial', align: 'right'
                    });
                    // 背景条
                    slide.addShape(pptx.ShapeType.roundRect, {
                        x: 0.7, y: y + 0.27, w: 5.1, h: 0.1,
                        fill: { color: 'e0e0e5' }, rectRadius: 0.05
                    });
                    // 进度条
                    slide.addShape(pptx.ShapeType.roundRect, {
                        x: 0.7, y: y + 0.27, w: 5.1 * bar.pct / 100, h: 0.1,
                        fill: { color: C.black }, rectRadius: 0.05
                    });
                });

                // 学习资源
                slide.addShape(pptx.ShapeType.roundRect, {
                    x: 6.7, y: 3.9, w: 5.8, h: 2.65,
                    fill: { color: C.lightGray }, line: { color: 'e8e8ed', width: 1 },
                    rectRadius: 0.12
                });
                slide.addText('🏆 推荐学习资源', {
                    x: 6.9, y: 4.03, w: 5.3, h: 0.28,
                    fontSize: 12, color: C.black, bold: true, fontFace: 'Arial'
                });
                const resources = [
                    { name: 'CTF 平台', desc: 'BUUCTF、攻防世界均有专项 Android 题' },
                    { name: 'OWASP MASTG', desc: '移动安全测试指南,官方免费 PDF' },
                    { name: '看雪论坛 / 52pojie', desc: '国内最活跃逆向社区,大量实战案例' },
                    { name: 'Android Internals', desc: 'Jonathan Levin 著,深入系统底层原理' },
                ];
                resources.forEach((r, i) => {
                    slide.addShape(pptx.ShapeType.roundRect, {
                        x: 6.9, y: 4.43 + i * 0.52, w: 5.3, h: 0.42,
                        fill: { color: C.white }, line: { color: 'e8e8ed', width: 1 },
                        rectRadius: 0.06
                    });
                    slide.addText(r.name, {
                        x: 7.1, y: 4.46 + i * 0.52, w: 2.5, h: 0.22,
                        fontSize: 10, color: C.black, bold: true, fontFace: 'Arial'
                    });
                    slide.addText(r.desc, {
                        x: 7.1, y: 4.67 + i * 0.52, w: 5, h: 0.18,
                        fontSize: 9, color: C.gray, fontFace: 'Arial'
                    });
                });

                slide.addText('ANDROID REVERSE ENGINEERING', {
                    x: 0.5, y: 7.0, w: 5, h: 0.25,
                    fontSize: 8, color: C.border, bold: true, fontFace: 'Arial'
                });
                slide.addText('08 / 10', {
                    x: 11.5, y: 7.0, w: 1.2, h: 0.25,
                    fontSize: 8, color: C.border, fontFace: 'Arial', align: 'right'
                });
            }

            // ──────────────────────────────
            // SLIDE 9: 法律
            // ──────────────────────────────
            {
                const slide = pptx.addSlide();
                slide.background = { color: C.white };

                slide.addShape(pptx.ShapeType.rect, {
                    x: 0, y: 0, w: 0.06, h: 7.5,
                    fill: { color: C.black }
                });
                slide.addText('CHAPTER 08', {
                    x: 0.5, y: 0.5, w: 4, h: 0.25,
                    fontSize: 9, color: C.gray, bold: true, fontFace: 'Arial', charSpacing: 1
                });
                slide.addShape(pptx.ShapeType.rect, {
                    x: 0.5, y: 0.82, w: 0.5, h: 0.04,
                    fill: { color: C.black }
                });
                slide.addText('法律红线与职业道德', {
                    x: 0.5, y: 0.95, w: 12, h: 0.7,
                    fontSize: 28, color: C.black, bold: true, fontFace: 'Arial'
                });

                // 表格头
                const tableHeaders = ['行为', '法律依据(中国)', '风险等级', '建议'];
                const tableWidths = [3.5, 3.0, 2.0, 4.2];
                let xOff = 0.5;
                slide.addShape(pptx.ShapeType.roundRect, {
                    x: 0.5, y: 1.85, w: 12.2, h: 0.38,
                    fill: { color: C.lightGray }, line: { color: 'e8e8ed', width: 1 },
                    rectRadius: 0.06
                });
                tableHeaders.forEach((h, i) => {
                    slide.addText(h, {
                        x: xOff + 0.1, y: 1.88, w: tableWidths[i] - 0.1, h: 0.32,
                        fontSize: 11, color: C.black, bold: true, fontFace: 'Arial'
                    });
                    xOff += tableWidths[i];
                });

                const rows = [
                    ['分析自己的 APP / 授权安全测试', '合法行为', '✓ 安全', '推荐练习方式'],
                    ['CTF 竞赛逆向题', '合法行为', '✓ 安全', '最佳入门途径'],
                    ['发现漏洞后负责任披露', '《网络安全法》鼓励', '✓ 鼓励', '可获 Bug Bounty 奖励'],
                    ['破解商业软件版权保护', '《著作权法》第 48 条', '⚠ 违法', '可能面临民事赔偿'],
                    ['未授权入侵、窃取数据', '《刑法》285/286 条', '🚫 刑事', '最高 7 年有期徒刑'],
                ];

                rows.forEach((row, ri) => {
                    const y = 2.28 + ri * 0.72;
                    const isOdd = ri % 2 === 0;
                    slide.addShape(pptx.ShapeType.rect, {
                        x: 0.5, y, w: 12.2, h: 0.68,
                        fill: { color: isOdd ? C.white : 'fafafa' }
                    });
                    // 底部分割线
                    slide.addShape(pptx.ShapeType.line, {
                        x: 0.5, y: y + 0.68, w: 12.2, h: 0,
                        line: { color: 'f0f0f0', width: 1 }
                    });
                    xOff = 0.5;
                    row.forEach((cell, ci) => {
                        const isDanger = ri >= 3;
                        const isRisk = ci === 2;
                        slide.addText(cell, {
                            x: xOff + 0.1, y: y + 0.2, w: tableWidths[ci] - 0.1, h: 0.28,
                            fontSize: 10,
                            color: isRisk && isDanger ? 'c0392b' : isRisk ? '27ae60' : C.gray,
                            bold: isRisk,
                            fontFace: 'Arial'
                        });
                        xOff += tableWidths[ci];
                    });
                });

                // 提示框
                slide.addShape(pptx.ShapeType.roundRect, {
                    x: 0.5, y: 5.95, w: 12.2, h: 0.75,
                    fill: { color: 'f0f8ff' }, line: { color: 'b3d9f7', width: 1 },
                    rectRadius: 0.08
                });
                slide.addText('⚖️  核心原则:只在你有权限的环境内操作。拿到认证(OSCE、BSCP)比非法操作更能体现技术价值。Bug Bounty 平台(HackerOne、各厂商 SRC)提供了合法赚钱的渠道,最高单漏洞奖励可达数万元。', {
                    x: 0.7, y: 6.02, w: 11.8, h: 0.6,
                    fontSize: 10, color: '1a4a7a', fontFace: 'Arial', lineSpacingMultiple: 1.3
                });

                slide.addText('ANDROID REVERSE ENGINEERING', {
                    x: 0.5, y: 7.0, w: 5, h: 0.25,
                    fontSize: 8, color: C.border, bold: true, fontFace: 'Arial'
                });
                slide.addText('09 / 10', {
                    x: 11.5, y: 7.0, w: 1.2, h: 0.25,
                    fontSize: 8, color: C.border, fontFace: 'Arial', align: 'right'
                });
            }

            // ──────────────────────────────
            // SLIDE 10: 学习路线
            // ──────────────────────────────
            {
                const slide = pptx.addSlide();
                slide.background = { color: C.white };

                slide.addShape(pptx.ShapeType.rect, {
                    x: 0, y: 0, w: 0.06, h: 7.5,
                    fill: { color: C.black }
                });
                slide.addText('CHAPTER 09', {
                    x: 0.5, y: 0.5, w: 4, h: 0.25,
                    fontSize: 9, color: C.gray, bold: true, fontFace: 'Arial', charSpacing: 1
                });
                slide.addShape(pptx.ShapeType.rect, {
                    x: 0.5, y: 0.82, w: 0.5, h: 0.04,
                    fill: { color: C.black }
                });
                slide.addText('从零到实战:学习路线图', {
                    x: 0.5, y: 0.95, w: 12, h: 0.7,
                    fontSize: 28, color: C.black, bold: true, fontFace: 'Arial'
                });

                // 时间线
                const timeline = [
                    { phase: '第 1-2 周:基础准备', desc: '学 Java 基础语法 → 了解 Android 开发结构 → 搭建 Android Studio 环境,写一个简单 APP', done: true },
                    { phase: '第 3-4 周:静态分析入门', desc: '安装 jadx,解析开源 APK(如 GadgetBridge),读懂类结构和方法调用关系', done: true },
                    { phase: '第 5-6 周:Smali 与重打包', desc: '用 apktool 解包 → 修改 Smali → 重打包签名 → 安装验证,完成第一次 patch', done: true },
                    { phase: '第 7-8 周:动态分析 Frida', desc: '配置 Frida 环境 → 完成基本 hook → 追踪加密函数 → 打印调用栈定位逻辑', done: true },
                    { phase: '第 2-3 月:CTF 实战', desc: '在 CTF 平台做 Android 题,解决真实混淆/加壳场景,积累实战解题经验', done: false },
                ];

                // 竖线
                slide.addShape(pptx.ShapeType.line, {
                    x: 0.9, y: 2.1, w: 0, h: 4.4,
                    line: { color: C.border, width: 1 }
                });

                timeline.forEach((item, i) => {
                    const y = 2.0 + i * 0.9;
                    // 圆点
                    slide.addShape(pptx.ShapeType.ellipse, {
                        x: 0.65, y: y + 0.02, w: 0.5, h: 0.5,
                        fill: { color: item.done ? C.black : C.white },
                        line: { color: item.done ? C.black : C.border, width: 2 }
                    });
                    if (item.done) {
                        slide.addText(String(i + 1), {
                            x: 0.65, y: y + 0.02, w: 0.5, h: 0.5,
                            fontSize: 11, color: C.white, bold: true,
                            fontFace: 'Arial', align: 'center', valign: 'middle'
                        });
                    }
                    slide.addText(item.phase, {
                        x: 1.3, y: y + 0.02, w: 5.1, h: 0.28,
                        fontSize: 12, color: C.black, bold: true, fontFace: 'Arial'
                    });
                    slide.addText(item.desc, {
                        x: 1.3, y: y + 0.32, w: 5.3, h: 0.45,
                        fontSize: 10, color: C.gray, fontFace: 'Arial', lineSpacingMultiple: 1.3
                    });
                });

                // 右侧:练习 APK + 技能树
                slide.addShape(pptx.ShapeType.roundRect, {
                    x: 7.1, y: 2.0, w: 5.6, h: 2.0,
                    fill: { color: C.lightGray }, line: { color: 'e8e8ed', width: 1 },
                    rectRadius: 0.12
                });
                slide.addText('🛠 推荐练习 APK', {
                    x: 7.3, y: 2.12, w: 5, h: 0.28,
                    fontSize: 12, color: C.black, bold: true, fontFace: 'Arial'
                });
                const apks = [
                    { name: 'InsecureBank v2', level: '入门' },
                    { name: 'DIVA Android', level: '入门' },
                    { name: 'UnCrackable Level 1-3', level: '进阶' },
                    { name: 'OWASP GoatDroid', level: '综合' },
                ];
                apks.forEach((apk, i) => {
                    slide.addShape(pptx.ShapeType.line, {
                        x: 7.3, y: 2.52 + i * 0.33, w: 5.1, h: 0,
                        line: { color: 'f0f0f0', width: 1 }
                    });
                    slide.addText(apk.name, {
                        x: 7.3, y: 2.55 + i * 0.33, w: 3.5, h: 0.25,
                        fontSize: 10, color: C.black, bold: true, fontFace: 'Arial'
                    });
                    slide.addText(apk.level, {
                        x: 11.2, y: 2.55 + i * 0.33, w: 1.2, h: 0.25,
                        fontSize: 9, color: C.gray, fontFace: 'Arial', align: 'right'
                    });
                });

                // 技能树
                slide.addShape(pptx.ShapeType.roundRect, {
                    x: 7.1, y: 4.15, w: 5.6, h: 2.4,
                    fill: { color: C.lightGray }, line: { color: 'e8e8ed', width: 1 },
                    rectRadius: 0.12
                });
                slide.addText('🎯 技能树总览', {
                    x: 7.3, y: 4.28, w: 5, h: 0.28,
                    fontSize: 12, color: C.black, bold: true, fontFace: 'Arial'
                });
                const skills = [
                    ['Java/Kotlin', 'Smali 语法'],
                    ['jadx 使用', 'apktool 重打包'],
                    ['Frida 插桩', '抓包分析'],
                    ['ARM 汇编 (进阶)', '脱壳技术 (进阶)'],
                ];
                skills.forEach((row, ri) => {
                    row.forEach((skill, ci) => {
                        const isAdv = skill.includes('进阶');
                        slide.addShape(pptx.ShapeType.roundRect, {
                            x: 7.3 + ci * 2.75, y: 4.68 + ri * 0.43, w: 2.55, h: 0.34,
                            fill: { color: isAdv ? 'f0f0f0' : C.white },
                            line: { color: 'e8e8ed', width: 1 },
                            rectRadius: 0.06
                        });
                        slide.addText(skill, {
                            x: 7.35 + ci * 2.75, y: 4.7 + ri * 0.43, w: 2.45, h: 0.3,
                            fontSize: 9.5,
                            color: isAdv ? C.gray : C.black,
                            bold: !isAdv,
                            fontFace: 'Arial', align: 'center'
                        });
                    });
                });

                slide.addText('ANDROID REVERSE ENGINEERING', {
                    x: 0.5, y: 7.0, w: 5, h: 0.25,
                    fontSize: 8, color: C.border, bold: true, fontFace: 'Arial'
                });
                slide.addText('10 / 10', {
                    x: 11.5, y: 7.0, w: 1.2, h: 0.25,
                    fontSize: 8, color: C.border, fontFace: 'Arial', align: 'right'
                });
            }

            // 保存文件
            await pptx.writeFile({ fileName: '安卓逆向工程简介.pptx' });

        } catch (error) {
            console.error('导出失败:', error);
            alert('导出失败: ' + error.message);
        } finally {
            loading.classList.add('hidden');
        }
    }

    function loadScript(src) {
        return new Promise((resolve, reject) => {
            if (window.PptxGenJS) {
                resolve();
                return;
            }
            const script = document.createElement('script');
            script.src = src;
            script.onload = resolve;
            script.onerror = reject;
            document.head.appendChild(script);
        });
    }

    // ============================================
    // 初始化
    // ============================================
    initSidebar();
    initProgress();
</script>
</body>
</html>

 

 
 
 
我们也可以设计多个提示词动态模板动态生成不同的ppt
 

 

image

 

 

下面是claude生成的代码

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>安卓逆向工程简介</title>
    <style>
        * { margin: 0; padding: 0; box-sizing: border-box; }

        body {
            font-family: 'Microsoft YaHei', '微软雅黑', sans-serif;
            background: #f0f2f5;
            color: #1a1a1a;
            overflow: hidden;
        }

        /* ===== 顶栏 ===== */
        .control-bar {
            position: fixed;
            top: 0; left: 0; right: 0;
            height: 54px;
            background: #ffffff;
            border-bottom: 1px solid #e0e4ea;
            display: flex;
            align-items: center;
            justify-content: space-between;
            padding: 0 24px;
            z-index: 1000;
        }

        .logo {
            font-size: 16px;
            font-weight: 700;
            color: #1a6bff;
            display: flex;
            align-items: center;
            gap: 8px;
        }

        .logo-icon {
            width: 32px; height: 32px;
            background: #1a6bff;
            border-radius: 8px;
            display: flex; align-items: center; justify-content: center;
            font-size: 16px;
            color: #fff;
        }

        .slide-counter {
            font-size: 13px;
            color: #888;
            background: #f0f2f5;
            padding: 4px 14px;
            border-radius: 20px;
            margin-left: 14px;
            font-weight: 500;
        }

        .ctrl-right { display: flex; align-items: center; gap: 10px; }

        .btn {
            padding: 8px 18px;
            border: none;
            border-radius: 8px;
            cursor: pointer;
            font-size: 13px;
            font-family: inherit;
            font-weight: 600;
            transition: all 0.2s;
            display: flex;
            align-items: center;
            gap: 6px;
        }

        .btn-nav {
            background: #f0f2f5;
            color: #555;
            border: 1px solid #dde1e8;
        }
        .btn-nav:hover:not(:disabled) { background: #e4e8f0; color: #222; }
        .btn-nav:disabled { opacity: 0.4; cursor: not-allowed; }

        .btn-export {
            background: #1a6bff;
            color: #fff;
        }
        .btn-export:hover { background: #0055e0; transform: translateY(-1px); }
        .btn-export:disabled { opacity: 0.5; cursor: not-allowed; transform: none; }

        /* 进度条 */
        .progress {
            position: fixed;
            top: 54px; left: 0;
            height: 3px;
            background: #1a6bff;
            transition: width 0.4s ease;
            z-index: 999;
        }

        /* 幻灯片区域 */
        .stage {
            position: fixed;
            top: 54px; left: 0; right: 0; bottom: 60px;
            display: flex;
            align-items: center;
            justify-content: center;
            padding: 16px;
        }

        .slide-wrap {
            position: relative;
            width: 100%;
            max-width: 1000px;
            aspect-ratio: 16/9;
        }

        .slide {
            position: absolute;
            inset: 0;
            border-radius: 12px;
            overflow: hidden;
            box-shadow: 0 4px 24px rgba(0,0,0,0.10);
            opacity: 0;
            transform: translateX(40px) scale(0.98);
            transition: all 0.4s cubic-bezier(0.4,0,0.2,1);
            pointer-events: none;
            background: #ffffff;
        }
        .slide.active { opacity: 1; transform: none; pointer-events: all; }
        .slide.exit-left { opacity: 0; transform: translateX(-40px) scale(0.98); }

        /* 底部 dots */
        .dots-bar {
            position: fixed;
            bottom: 0; left: 0; right: 0;
            height: 60px;
            background: #ffffff;
            border-top: 1px solid #e0e4ea;
            display: flex;
            align-items: center;
            justify-content: center;
            gap: 8px;
        }

        .dot {
            width: 8px; height: 8px;
            border-radius: 50%;
            background: #d0d5df;
            cursor: pointer;
            transition: all 0.25s;
        }
        .dot.active {
            width: 28px;
            border-radius: 4px;
            background: #1a6bff;
        }
        .dot:hover:not(.active) { background: #aab0c0; }

        /* Toast */
        .toast {
            position: fixed;
            top: 64px; right: 20px;
            padding: 11px 20px;
            border-radius: 10px;
            font-size: 13px;
            font-weight: 500;
            transform: translateY(-8px);
            opacity: 0;
            transition: all 0.3s;
            z-index: 2000;
            pointer-events: none;
        }
        .toast.show { transform: translateY(0); opacity: 1; }
        .toast.info { background: #e8f0ff; border: 1px solid #b0caff; color: #1a6bff; }
        .toast.success { background: #e8f8ef; border: 1px solid #a0ddb5; color: #0a8040; }
        .toast.error { background: #fff0f0; border: 1px solid #ffbbbb; color: #cc2200; }

        .key-hint {
            position: fixed;
            bottom: 70px; right: 16px;
            font-size: 11px;
            color: #bbb;
        }

        /* ===================================================
           通用幻灯片布局元素
        =================================================== */
        .slide-inner { position: relative; width: 100%; height: 100%; }

        /* 左侧色带 */
        .left-accent {
            position: absolute;
            left: 0; top: 0; bottom: 0;
            width: 5px;
        }

        /* 顶部标签 */
        .s-label {
            font-size: 10px;
            font-weight: 700;
            letter-spacing: 2.5px;
            text-transform: uppercase;
            margin-bottom: 5px;
        }

        .s-title {
            font-size: 24px;
            font-weight: 900;
            color: #1a1a1a;
            line-height: 1.25;
        }

        .hl { color: #1a6bff; }
        .hl-red { color: #e03030; }
        .hl-green { color: #0a8040; }
        .hl-orange { color: #e06800; }

        /* ===== 第1页 封面 ===== */
        .cover-slide {
            width: 100%; height: 100%;
            display: flex;
        }

        .cover-left {
            width: 55%;
            background: #1a6bff;
            display: flex;
            flex-direction: column;
            justify-content: center;
            padding: 40px 44px;
            position: relative;
            overflow: hidden;
        }

        .cover-left::before {
            content: '';
            position: absolute;
            bottom: -60px; right: -60px;
            width: 220px; height: 220px;
            background: rgba(255,255,255,0.08);
            border-radius: 50%;
        }
        .cover-left::after {
            content: '';
            position: absolute;
            top: -40px; left: -40px;
            width: 140px; height: 140px;
            background: rgba(255,255,255,0.06);
            border-radius: 50%;
        }

        .cover-badge {
            display: inline-flex;
            align-items: center;
            gap: 6px;
            background: rgba(255,255,255,0.15);
            border: 1px solid rgba(255,255,255,0.25);
            border-radius: 20px;
            padding: 4px 14px;
            font-size: 10px;
            color: rgba(255,255,255,0.9);
            letter-spacing: 2px;
            margin-bottom: 20px;
            width: fit-content;
        }

        .cover-main-title {
            font-size: 38px;
            font-weight: 900;
            color: #fff;
            line-height: 1.15;
            margin-bottom: 8px;
        }

        .cover-sub-title {
            font-size: 16px;
            font-weight: 400;
            color: rgba(255,255,255,0.75);
            margin-bottom: 28px;
        }

        .cover-divider {
            width: 40px; height: 3px;
            background: rgba(255,255,255,0.5);
            border-radius: 2px;
            margin-bottom: 20px;
        }

        .cover-en {
            font-size: 11px;
            color: rgba(255,255,255,0.5);
            letter-spacing: 1.5px;
        }

        .cover-right {
            flex: 1;
            background: #ffffff;
            display: flex;
            flex-direction: column;
            justify-content: center;
            padding: 32px 36px;
        }

        .cover-right-label {
            font-size: 11px;
            font-weight: 700;
            color: #1a6bff;
            letter-spacing: 2px;
            text-transform: uppercase;
            margin-bottom: 20px;
        }

        .cover-tag-list {
            display: flex;
            flex-direction: column;
            gap: 10px;
        }

        .cover-tag-item {
            display: flex;
            align-items: center;
            gap: 12px;
            padding: 11px 14px;
            background: #f7f9fc;
            border: 1px solid #e8ecf2;
            border-radius: 8px;
            font-size: 12px;
            color: #333;
            font-weight: 500;
        }

        .cover-tag-icon {
            width: 28px; height: 28px;
            background: #1a6bff;
            border-radius: 7px;
            display: flex; align-items: center; justify-content: center;
            font-size: 13px;
            flex-shrink: 0;
        }

        /* ===== 第2页 目录 ===== */
        .toc-layout { display: flex; height: 100%; }

        .toc-left {
            width: 220px;
            background: #1a6bff;
            display: flex;
            flex-direction: column;
            justify-content: center;
            padding: 0 30px;
            flex-shrink: 0;
        }

        .toc-left-label {
            font-size: 10px;
            font-weight: 700;
            letter-spacing: 3px;
            color: rgba(255,255,255,0.65);
            text-transform: uppercase;
            margin-bottom: 10px;
        }

        .toc-left-title {
            font-size: 30px;
            font-weight: 900;
            color: #fff;
            line-height: 1.2;
            margin-bottom: 16px;
        }

        .toc-divider {
            width: 36px; height: 3px;
            background: rgba(255,255,255,0.4);
            border-radius: 2px;
        }

        .toc-right {
            flex: 1;
            background: #ffffff;
            display: flex;
            flex-direction: column;
            justify-content: center;
            gap: 8px;
            padding: 24px 28px;
        }

        .toc-row {
            display: flex;
            align-items: center;
            gap: 14px;
            padding: 11px 14px;
            background: #f7f9fc;
            border: 1px solid #e8ecf2;
            border-radius: 8px;
            cursor: default;
            transition: all 0.2s;
        }
        .toc-row:hover { background: #edf2ff; border-color: #b8d0ff; transform: translateX(3px); }

        .toc-num {
            width: 30px; height: 30px;
            border-radius: 7px;
            background: #1a6bff;
            display: flex; align-items: center; justify-content: center;
            font-size: 12px; font-weight: 700; color: #fff;
            flex-shrink: 0;
        }

        .toc-info h4 { font-size: 13px; font-weight: 600; color: #1a1a1a; margin-bottom: 1px; }
        .toc-info p { font-size: 10px; color: #999; }
        .toc-arr { margin-left: auto; color: #1a6bff; font-size: 15px; font-weight: 700; }

        /* ===== 第3页 简介 ===== */
        .intro-layout {
            display: flex; height: 100%;
        }

        .intro-left {
            flex: 1;
            padding: 28px 28px 24px;
            display: flex;
            flex-direction: column;
            justify-content: center;
            border-right: 1px solid #e8ecf2;
        }

        .intro-right {
            width: 240px;
            background: #f7f9fc;
            display: flex;
            flex-direction: column;
            justify-content: center;
            gap: 0;
            padding: 18px 16px;
        }

        .def-box {
            background: #edf2ff;
            border-left: 4px solid #1a6bff;
            border-radius: 0 8px 8px 0;
            padding: 12px 14px;
            margin-bottom: 18px;
            font-size: 12px;
            color: #333;
            line-height: 1.75;
        }

        .def-box strong { color: #1a6bff; }

        .pts { display: flex; flex-direction: column; gap: 9px; }
        .pt { display: flex; align-items: flex-start; gap: 9px; font-size: 12px; color: #444; }
        .pt-dot {
            width: 6px; height: 6px;
            border-radius: 50%;
            background: #1a6bff;
            flex-shrink: 0;
            margin-top: 4px;
        }
        .pt-dot.warn { background: #e06800; }

        .flow-card {
            background: #ffffff;
            border: 1px solid #e0e4ea;
            border-radius: 8px;
            padding: 9px 12px;
            display: flex;
            align-items: center;
            gap: 10px;
        }

        .flow-card.active-card {
            background: #edf2ff;
            border-color: #b8d0ff;
        }

        .flow-icon { font-size: 18px; }
        .flow-card h4 { font-size: 11.5px; font-weight: 700; color: #1a1a1a; margin-bottom: 1px; }
        .flow-card p { font-size: 9.5px; color: #999; }

        .flow-arr {
            text-align: center;
            color: #1a6bff;
            font-size: 14px;
            padding: 3px 0;
        }

        /* ===== 第4页 工具链 ===== */
        .tools-wrap { height: 100%; padding: 24px 28px; display: flex; flex-direction: column; background: #fff; }

        .page-header { margin-bottom: 14px; }

        .tools-grid {
            display: grid;
            grid-template-columns: repeat(3, 1fr);
            gap: 10px;
            flex: 1;
            align-content: center;
        }

        .tool-card {
            background: #f7f9fc;
            border: 1px solid #e8ecf2;
            border-radius: 10px;
            padding: 14px;
            transition: all 0.2s;
        }
        .tool-card:hover { background: #edf2ff; border-color: #b8d0ff; transform: translateY(-2px); }

        .tc-head { display: flex; align-items: center; gap: 10px; margin-bottom: 8px; }

        .tc-ico {
            width: 34px; height: 34px;
            border-radius: 8px;
            display: flex; align-items: center; justify-content: center;
            font-size: 17px; flex-shrink: 0;
        }

        .tc-head h4 { font-size: 13px; font-weight: 700; color: #1a1a1a; }
        .tc-type { font-size: 9.5px; color: #999; margin-top: 1px; }

        .tool-card p { font-size: 10.5px; color: #666; line-height: 1.6; }

        .tc-tags { display: flex; gap: 4px; margin-top: 9px; flex-wrap: wrap; }
        .tc-tag {
            font-size: 9.5px;
            background: #e8f0ff;
            color: #1a6bff;
            border-radius: 4px;
            padding: 2px 8px;
            font-weight: 600;
        }

        /* ===== 第5页 APK结构 ===== */
        .apk-layout {
            display: flex; height: 100%;
            background: #fff;
        }

        .apk-left {
            flex: 1;
            padding: 26px 24px;
            border-right: 1px solid #e8ecf2;
            display: flex;
            flex-direction: column;
        }

        .apk-right {
            width: 272px;
            background: #f7f9fc;
            display: flex;
            flex-direction: column;
            gap: 6px;
            justify-content: center;
            padding: 16px;
        }

        .tree-box {
            background: #1a1a2a;
            border-radius: 10px;
            padding: 14px 16px;
            font-family: 'Courier New', monospace;
            font-size: 11px;
            line-height: 1.9;
            flex: 1;
            margin-top: 12px;
            overflow: hidden;
        }

        .t-root { color: #5bb8ff; font-weight: 700; }
        .t-yellow { color: #f0c040; }
        .t-blue { color: #7b9cff; }
        .t-green { color: #4caf50; }
        .t-gray { color: #666888; }

        .struct-card {
            padding: 10px 12px;
            border-radius: 7px;
            border-left: 3px solid;
            background: #ffffff;
            border-top: 1px solid #e8ecf2;
            border-right: 1px solid #e8ecf2;
            border-bottom: 1px solid #e8ecf2;
        }
        .struct-card h5 { font-size: 11px; font-weight: 700; margin-bottom: 3px; }
        .struct-card p { font-size: 10px; color: #888; line-height: 1.5; }

        /* ===== 第6页 技术 ===== */
        .tech-wrap { height: 100%; padding: 24px 28px; display: flex; flex-direction: column; background: #fff; }

        .tech-grid {
            display: grid;
            grid-template-columns: repeat(2, 1fr);
            gap: 10px;
            flex: 1;
            align-content: center;
        }

        .tech-card {
            background: #f7f9fc;
            border: 1px solid #e8ecf2;
            border-radius: 10px;
            padding: 14px;
            display: flex;
            gap: 12px;
            transition: all 0.2s;
        }
        .tech-card:hover { background: #edf2ff; border-color: #b8d0ff; }

        .tc-icon-box {
            width: 40px; height: 40px;
            border-radius: 9px;
            display: flex; align-items: center; justify-content: center;
            font-size: 19px; flex-shrink: 0;
        }

        .tech-card h4 { font-size: 13px; font-weight: 700; color: #1a1a1a; margin-bottom: 5px; }
        .tech-card p { font-size: 11px; color: #666; line-height: 1.6; }

        /* ===== 第7页 防护 ===== */
        .def-slide {
            display: flex; flex-direction: column;
            height: 100%; background: #fff;
        }

        .def-page-header {
            padding: 20px 28px 12px;
            border-bottom: 1px solid #e8ecf2;
        }

        .def-body {
            display: flex; flex: 1; overflow: hidden;
        }

        .def-col {
            flex: 1;
            display: flex;
            flex-direction: column;
            gap: 8px;
            padding: 14px 18px;
        }

        .def-col-left { border-right: 1px solid #e8ecf2; }

        .def-hdr {
            display: flex; align-items: center; gap: 8px;
            padding: 9px 13px;
            border-radius: 8px;
            font-size: 13px; font-weight: 700;
            margin-bottom: 2px;
        }

        .def-hdr.atk {
            background: #fff0f0;
            border: 1px solid #ffc0c0;
            color: #cc2200;
        }

        .def-hdr.prt {
            background: #edf2ff;
            border: 1px solid #b8d0ff;
            color: #1a6bff;
        }

        .def-item {
            padding: 9px 12px;
            border-radius: 7px;
            background: #f7f9fc;
            border: 1px solid #e8ecf2;
            display: flex; align-items: flex-start; gap: 8px;
            transition: all 0.2s;
        }
        .def-item:hover { border-color: #c8d8ff; background: #f0f5ff; }

        .di-ico { font-size: 15px; flex-shrink: 0; margin-top: 1px; }
        .di-c h5 { font-size: 11.5px; font-weight: 600; color: #1a1a1a; margin-bottom: 2px; }
        .di-c p { font-size: 10px; color: #888; line-height: 1.5; }

        .vs-sep {
            width: 1px;
            background: #e8ecf2;
            display: flex;
            align-items: center;
            justify-content: center;
            position: relative;
        }

        .vs-txt {
            position: absolute;
            background: #fff;
            border: 2px solid #e8ecf2;
            color: #bbb;
            font-size: 10px;
            font-weight: 700;
            width: 30px; height: 30px;
            border-radius: 50%;
            display: flex; align-items: center; justify-content: center;
        }

        /* ===== 第8页 总结 ===== */
        .end-slide {
            display: flex; flex-direction: column;
            height: 100%; background: #fff;
        }

        .end-top {
            background: #1a6bff;
            padding: 28px 36px 24px;
            display: flex;
            flex-direction: column;
            align-items: center;
            text-align: center;
        }

        .end-icon { font-size: 42px; margin-bottom: 10px; }

        .end-title {
            font-size: 26px;
            font-weight: 900;
            color: #fff;
            margin-bottom: 8px;
        }

        .end-desc {
            font-size: 12px;
            color: rgba(255,255,255,0.75);
            line-height: 1.7;
            max-width: 560px;
        }

        .end-bottom {
            flex: 1;
            padding: 18px 28px 16px;
            display: flex;
            flex-direction: column;
            gap: 14px;
        }

        .stage-cards {
            display: flex;
            gap: 12px;
            justify-content: center;
        }

        .stage-card {
            background: #f7f9fc;
            border: 1px solid #e8ecf2;
            border-radius: 10px;
            padding: 14px 16px;
            flex: 1;
            text-align: center;
            transition: all 0.2s;
        }
        .stage-card:hover { background: #edf2ff; border-color: #b8d0ff; }

        .stage-card .si { font-size: 22px; margin-bottom: 7px; }
        .stage-card h5 { font-size: 12.5px; font-weight: 700; color: #1a1a1a; margin-bottom: 6px; }
        .stage-card p { font-size: 10.5px; color: #888; line-height: 1.7; }

        .warn-box {
            background: #fffbec;
            border: 1px solid #f0d060;
            border-radius: 8px;
            padding: 10px 16px;
            font-size: 11.5px;
            color: #886600;
            display: flex; align-items: center; gap: 8px;
        }
    </style>
</head>
<body>

<div class="progress" id="prog" style="width:12.5%"></div>

<!-- 顶栏 -->
<div class="control-bar">
    <div style="display:flex;align-items:center">
        <div class="logo">
            <div class="logo-icon">🔐</div>
            AndroidRev
        </div>
        <div class="slide-counter" id="counter">1 / 8</div>
    </div>
    <div class="ctrl-right">
        <button class="btn btn-nav" id="btnPrev" onclick="go(-1)" disabled>◀ 上一页</button>
        <button class="btn btn-nav" id="btnNext" onclick="go(1)">下一页 ▶</button>
        <button class="btn btn-export" id="btnExport" onclick="doExport()">📥 导出 PPTX</button>
    </div>
</div>

<div class="toast" id="toast"></div>

<!-- 幻灯片区域 -->
<div class="stage">
    <div class="slide-wrap" id="slideWrap">

        <!-- ========== 第1页:封面 ========== -->
        <div class="slide active">
            <div class="cover-slide">
                <div class="cover-left">
                    <div class="cover-badge">● SECURITY RESEARCH</div>
                    <h1 class="cover-main-title">安卓逆向工程</h1>
                    <p class="cover-sub-title">入门与实践简介</p>
                    <div class="cover-divider"></div>
                    <p class="cover-en">Android Reverse Engineering · Introduction</p>
                </div>
                <div class="cover-right">
                    <div class="cover-right-label">课程涵盖内容</div>
                    <div class="cover-tag-list">
                        <div class="cover-tag-item">
                            <div class="cover-tag-icon">📦</div>
                            <span>APK 安装包分析与解包技术</span>
                        </div>
                        <div class="cover-tag-item">
                            <div class="cover-tag-icon">🔍</div>
                            <span>静态代码反编译与阅读</span>
                        </div>
                        <div class="cover-tag-item">
                            <div class="cover-tag-icon">🐛</div>
                            <span>动态调试与运行时插桩</span>
                        </div>
                        <div class="cover-tag-item">
                            <div class="cover-tag-icon">🛡️</div>
                            <span>安全研究与防护对抗</span>
                        </div>
                        <div class="cover-tag-item">
                            <div class="cover-tag-icon">⚙️</div>
                            <span>Frida Hook 实战应用</span>
                        </div>
                    </div>
                </div>
            </div>
        </div>

        <!-- ========== 第2页:目录 ========== -->
        <div class="slide">
            <div class="toc-layout">
                <div class="toc-left">
                    <div class="toc-left-label">CONTENTS</div>
                    <div class="toc-left-title">课程<br>目录</div>
                    <div class="toc-divider"></div>
                </div>
                <div class="toc-right">
                    <div class="toc-row">
                        <div class="toc-num">01</div>
                        <div class="toc-info"><h4>什么是安卓逆向</h4><p>概念定义与应用场景</p></div>
                        <span class="toc-arr">›</span>
                    </div>
                    <div class="toc-row">
                        <div class="toc-num">02</div>
                        <div class="toc-info"><h4>核心工具链</h4><p>必备工具与环境搭建</p></div>
                        <span class="toc-arr">›</span>
                    </div>
                    <div class="toc-row">
                        <div class="toc-num">03</div>
                        <div class="toc-info"><h4>APK 文件结构</h4><p>深入了解安装包组成</p></div>
                        <span class="toc-arr">›</span>
                    </div>
                    <div class="toc-row">
                        <div class="toc-num">04</div>
                        <div class="toc-info"><h4>常用逆向技术</h4><p>静态 / 动态分析方法</p></div>
                        <span class="toc-arr">›</span>
                    </div>
                    <div class="toc-row">
                        <div class="toc-num">05</div>
                        <div class="toc-info"><h4>防护与反制措施</h4><p>加固方案 vs 绕过技术</p></div>
                        <span class="toc-arr">›</span>
                    </div>
                    <div class="toc-row">
                        <div class="toc-num">06</div>
                        <div class="toc-info"><h4>总结与学习路线</h4><p>进阶方向与资源推荐</p></div>
                        <span class="toc-arr">›</span>
                    </div>
                </div>
            </div>
        </div>

        <!-- ========== 第3页:什么是逆向 ========== -->
        <div class="slide">
            <div class="intro-layout">
                <div class="intro-left">
                    <div class="s-label" style="color:#1a6bff;margin-bottom:4px">01 · INTRODUCTION</div>
                    <div class="s-title" style="margin-bottom:14px">什么是<span class="hl">安卓逆向</span>工程?</div>
                    <div class="def-box">
                        安卓逆向工程是指在<strong>不具备源码</strong>的情况下,通过对 APK 文件进行反编译、分析和调试,理解应用程序内部逻辑、数据流程和安全机制的技术手段。
                    </div>
                    <div class="pts">
                        <div class="pt"><span class="pt-dot"></span><span><strong style="color:#1a1a1a">漏洞挖掘:</strong>发现 App 中的安全漏洞与隐私泄露风险</span></div>
                        <div class="pt"><span class="pt-dot"></span><span><strong style="color:#1a1a1a">恶意分析:</strong>分析病毒、木马等恶意程序的行为特征</span></div>
                        <div class="pt"><span class="pt-dot"></span><span><strong style="color:#1a1a1a">兼容适配:</strong>理解第三方 SDK 行为,辅助兼容性开发</span></div>
                        <div class="pt"><span class="pt-dot"></span><span><strong style="color:#1a1a1a">安全审计:</strong>对自身产品进行渗透测试与合规检测</span></div>
                        <div class="pt"><span class="pt-dot warn"></span><span style="color:#886600"><strong>重要提示:</strong>仅限合法授权范围内使用,切勿用于违法活动</span></div>
                    </div>
                </div>
                <div class="intro-right">
                    <div class="flow-card"><div class="flow-icon">📦</div><div><h4>APK 安装包</h4><p>目标文件</p></div></div>
                    <div class="flow-arr">↓</div>
                    <div class="flow-card"><div class="flow-icon">🔧</div><div><h4>反编译 / 解包</h4><p>工具处理阶段</p></div></div>
                    <div class="flow-arr">↓</div>
                    <div class="flow-card"><div class="flow-icon">🔍</div><div><h4>静态分析</h4><p>代码逻辑阅读</p></div></div>
                    <div class="flow-arr">↓</div>
                    <div class="flow-card"><div class="flow-icon">🐛</div><div><h4>动态调试</h4><p>运行时行为监控</p></div></div>
                    <div class="flow-arr">↓</div>
                    <div class="flow-card active-card"><div class="flow-icon">💡</div><div><h4>分析结论</h4><p>漏洞 / 逻辑 / 算法</p></div></div>
                </div>
            </div>
        </div>

        <!-- ========== 第4页:工具链 ========== -->
        <div class="slide">
            <div class="tools-wrap">
                <div class="page-header">
                    <div class="s-label" style="color:#1a6bff">02 · TOOLS</div>
                    <div class="s-title">核心<span class="hl">工具链</span>全景</div>
                </div>
                <div class="tools-grid">
                    <div class="tool-card">
                        <div class="tc-head">
                            <div class="tc-ico" style="background:#e8f0ff">🔨</div>
                            <div><h4>Jadx</h4><div class="tc-type">反编译工具</div></div>
                        </div>
                        <p>将 DEX/APK 反编译为可读的 Java 源码,支持图形界面,是最常用的静态分析工具。</p>
                        <div class="tc-tags"><span class="tc-tag">静态</span><span class="tc-tag">Java</span><span class="tc-tag">开源</span></div>
                    </div>
                    <div class="tool-card">
                        <div class="tc-head">
                            <div class="tc-ico" style="background:#f0ebff">📋</div>
                            <div><h4>Apktool</h4><div class="tc-type">资源解包工具</div></div>
                        </div>
                        <p>反编译 APK 为 Smali 中间代码,支持修改后重新打包,常用于代码插桩与修改。</p>
                        <div class="tc-tags"><span class="tc-tag">Smali</span><span class="tc-tag">重打包</span><span class="tc-tag">资源</span></div>
                    </div>
                    <div class="tool-card">
                        <div class="tc-head">
                            <div class="tc-ico" style="background:#fff2e8">🐛</div>
                            <div><h4>Frida</h4><div class="tc-type">动态插桩框架</div></div>
                        </div>
                        <p>强大的动态插桩工具,可在运行时 Hook Java/Native 函数,拦截参数与返回值。</p>
                        <div class="tc-tags"><span class="tc-tag">动态</span><span class="tc-tag">Hook</span><span class="tc-tag">Python</span></div>
                    </div>
                    <div class="tool-card">
                        <div class="tc-head">
                            <div class="tc-ico" style="background:#eafaf0">🌐</div>
                            <div><h4>Burp Suite</h4><div class="tc-type">流量抓包工具</div></div>
                        </div>
                        <p>中间人代理工具,拦截分析 HTTP/HTTPS 流量,配合 SSL Unpinning 完成接口分析。</p>
                        <div class="tc-tags"><span class="tc-tag">抓包</span><span class="tc-tag">HTTPS</span><span class="tc-tag">API</span></div>
                    </div>
                    <div class="tool-card">
                        <div class="tc-head">
                            <div class="tc-ico" style="background:#fff0f0">🏔️</div>
                            <div><h4>IDA Pro</h4><div class="tc-type">反汇编分析器</div></div>
                        </div>
                        <p>业界顶级反汇编工具,支持 ARM/x86 架构,用于分析 Native .so 库文件。</p>
                        <div class="tc-tags"><span class="tc-tag">NDK</span><span class="tc-tag">ARM</span><span class="tc-tag">汇编</span></div>
                    </div>
                    <div class="tool-card">
                        <div class="tc-head">
                            <div class="tc-ico" style="background:#e8f5ff">📱</div>
                            <div><h4>ADB + Logcat</h4><div class="tc-type">调试桥接工具</div></div>
                        </div>
                        <p>Android 调试桥,支持安装应用、查看日志、文件传输、Shell 命令执行等操作。</p>
                        <div class="tc-tags"><span class="tc-tag">官方</span><span class="tc-tag">日志</span><span class="tc-tag">Shell</span></div>
                    </div>
                </div>
            </div>
        </div>

        <!-- ========== 第5页:APK结构 ========== -->
        <div class="slide">
            <div class="apk-layout">
                <div class="apk-left">
                    <div class="s-label" style="color:#1a6bff">03 · STRUCTURE</div>
                    <div class="s-title">APK <span class="hl">文件结构</span>解析</div>
                    <div class="tree-box">
                        <div class="t-root">📦 example.apk &nbsp;(ZIP 格式)</div>
                        <div class="t-yellow">├── 📄 classes.dex &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;← Dalvik 字节码</div>
                        <div class="t-blue">├── 📄 classes2.dex &nbsp;&nbsp;&nbsp;&nbsp;← 多 DEX 支持</div>
                        <div class="t-yellow">├── 📄 AndroidManifest.xml</div>
                        <div class="t-gray">├── 📁 res/ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;← 资源文件</div>
                        <div class="t-gray">&nbsp;&nbsp;&nbsp;&nbsp;├── layout/</div>
                        <div class="t-gray">&nbsp;&nbsp;&nbsp;&nbsp;└── drawable/</div>
                        <div class="t-green">├── 📄 resources.arsc &nbsp;&nbsp;← 资源索引表</div>
                        <div class="t-blue">├── 📁 assets/ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;← 原始资源</div>
                        <div class="t-yellow">├── 📁 lib/ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;← Native 库</div>
                        <div class="t-gray">&nbsp;&nbsp;&nbsp;&nbsp;├── arm64-v8a/</div>
                        <div class="t-gray">&nbsp;&nbsp;&nbsp;&nbsp;└── armeabi-v7a/</div>
                        <div class="t-green">└── 📁 META-INF/ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;← 签名信息</div>
                    </div>
                </div>
                <div class="apk-right">
                    <div class="struct-card" style="border-left-color:#1a6bff"><h5 style="color:#1a6bff">📄 classes.dex</h5><p>Dalvik 可执行文件,包含所有 Java/Kotlin 编译后的字节码,是逆向的核心目标。</p></div>
                    <div class="struct-card" style="border-left-color:#7b2ff7"><h5 style="color:#7b2ff7">📄 AndroidManifest</h5><p>应用配置清单,包含权限申请、组件注册、版本信息等关键配置。</p></div>
                    <div class="struct-card" style="border-left-color:#e06800"><h5 style="color:#e06800">📁 lib/</h5><p>Native C/C++ 编译的 .so 动态链接库,常含核心算法和加密逻辑。</p></div>
                    <div class="struct-card" style="border-left-color:#0a8040"><h5 style="color:#0a8040">📁 META-INF/</h5><p>存储 APK 签名文件(CERT.RSA),用于验证应用完整性与来源。</p></div>
                    <div class="struct-card" style="border-left-color:#aaa"><h5 style="color:#666">📁 assets/</h5><p>原始资源文件,可能存放加密配置、H5 资源或二次加密的 DEX 文件。</p></div>
                </div>
            </div>
        </div>

        <!-- ========== 第6页:常用技术 ========== -->
        <div class="slide">
            <div class="tech-wrap">
                <div class="page-header">
                    <div class="s-label" style="color:#1a6bff">04 · TECHNIQUES</div>
                    <div class="s-title">常用<span class="hl">逆向技术</span>总览</div>
                </div>
                <div class="tech-grid">
                    <div class="tech-card">
                        <div class="tc-icon-box" style="background:#e8f0ff">🔍</div>
                        <div><h4>静态代码分析</h4><p>使用 Jadx 将 DEX 反编译为 Java 代码,分析业务逻辑、加密算法、API 接口。无需运行程序,风险低。</p></div>
                    </div>
                    <div class="tech-card">
                        <div class="tc-icon-box" style="background:#f0ebff">🐛</div>
                        <div><h4>动态调试与插桩</h4><p>通过 Frida / Xposed 在运行时 Hook 关键函数,实时获取参数、返回值,追踪代码执行流。</p></div>
                    </div>
                    <div class="tech-card">
                        <div class="tc-icon-box" style="background:#fff2e8">✏️</div>
                        <div><h4>Smali 代码插桩</h4><p>使用 Apktool 解包为 Smali,手动修改字节码逻辑后重新打包签名,绕过限制或添加调试代码。</p></div>
                    </div>
                    <div class="tech-card">
                        <div class="tc-icon-box" style="background:#eafaf0">🌐</div>
                        <div><h4>网络流量分析</h4><p>使用 Burp Suite 代理拦截 HTTP/HTTPS 流量,配合 SSL Unpinning 绕过证书校验,还原接口协议。</p></div>
                    </div>
                    <div class="tech-card">
                        <div class="tc-icon-box" style="background:#fff0f0">💾</div>
                        <div><h4>内存 Dump 分析</h4><p>对运行中的进程进行内存转储,提取解密后的 DEX、密钥、敏感数据,突破加固保护层。</p></div>
                    </div>
                    <div class="tech-card">
                        <div class="tc-icon-box" style="background:#e8f5ff">🏔️</div>
                        <div><h4>Native 层分析</h4><p>使用 IDA Pro / Ghidra 分析 .so 汇编代码,还原 Native 加密函数与核心算法逻辑。</p></div>
                    </div>
                </div>
            </div>
        </div>

        <!-- ========== 第7页:防护与反制 ========== -->
        <div class="slide">
            <div class="def-slide">
                <div class="def-page-header">
                    <div class="s-label" style="color:#1a6bff">05 · DEFENSE &amp; ATTACK</div>
                    <div class="s-title">防护<span class="hl">加固</span> vs 逆向<span class="hl-red">反制</span></div>
                </div>
                <div class="def-body">
                    <div class="def-col def-col-left">
                        <div class="def-hdr atk">🔥 逆向 / 攻击手段</div>
                        <div class="def-item"><span class="di-ico">🔓</span><div class="di-c"><h5>反调试绕过</h5><p>Hook ptrace / TracerPid 检测,欺骗反调试校验逻辑</p></div></div>
                        <div class="def-item"><span class="di-ico">📡</span><div class="di-c"><h5>SSL Pinning 绕过</h5><p>Frida Hook 证书验证函数,实现中间人流量抓包</p></div></div>
                        <div class="def-item"><span class="di-ico">💉</span><div class="di-c"><h5>内存 Dump 脱壳</h5><p>在 DEX 加载完毕后从内存中提取原始代码文件</p></div></div>
                        <div class="def-item"><span class="di-ico">🔄</span><div class="di-c"><h5>模拟器环境伪装</h5><p>修改设备指纹参数绕过模拟器检测逻辑</p></div></div>
                        <div class="def-item"><span class="di-ico">✏️</span><div class="di-c"><h5>重打包与签名伪造</h5><p>修改 Smali 代码后重新打包,绕过签名校验</p></div></div>
                    </div>
                    <div class="vs-sep"><div class="vs-txt">VS</div></div>
                    <div class="def-col">
                        <div class="def-hdr prt">🛡️ 防护 / 加固手段</div>
                        <div class="def-item"><span class="di-ico">🔐</span><div class="di-c"><h5>代码混淆</h5><p>ProGuard/R8 混淆类名、方法名,增加阅读难度</p></div></div>
                        <div class="def-item"><span class="di-ico">📦</span><div class="di-c"><h5>DEX 加壳加固</h5><p>梆梆、360加固等方案加密 DEX,运行时解密加载</p></div></div>
                        <div class="def-item"><span class="di-ico">🔍</span><div class="di-c"><h5>反调试检测</h5><p>检测 TracerPid、Frida 特征值、调试端口占用</p></div></div>
                        <div class="def-item"><span class="di-ico">✅</span><div class="di-c"><h5>签名完整性校验</h5><p>运行时验证 APK 签名哈希,防止重打包篡改</p></div></div>
                        <div class="def-item"><span class="di-ico">📌</span><div class="di-c"><h5>SSL Certificate Pinning</h5><p>内置服务器证书指纹,防止流量中间人攻击</p></div></div>
                    </div>
                </div>
            </div>
        </div>

        <!-- ========== 第8页:总结 ========== -->
        <div class="slide">
            <div class="end-slide">
                <div class="end-top">
                    <div class="end-icon">🎯</div>
                    <h2 class="end-title">总结与学习路线</h2>
                    <p class="end-desc">安卓逆向是一门综合性极强的技术,涵盖 Java/Smali/ARM 汇编、网络协议、密码学等多个领域。建议从基础工具入手,循序渐进,逐步深入 Native 层分析与协议还原。</p>
                </div>
                <div class="end-bottom">
                    <div class="stage-cards">
                        <div class="stage-card">
                            <div class="si">📚</div>
                            <h5>基础阶段</h5>
                            <p>Java/Kotlin<br>ADB 调试<br>Jadx 使用</p>
                        </div>
                        <div class="stage-card">
                            <div class="si">🔧</div>
                            <h5>进阶阶段</h5>
                            <p>Frida Hook<br>Smali 分析<br>Burp 抓包</p>
                        </div>
                        <div class="stage-card">
                            <div class="si">🏔️</div>
                            <h5>高级阶段</h5>
                            <p>IDA Pro<br>脱壳技术<br>协议还原</p>
                        </div>
                        <div class="stage-card">
                            <div class="si">🛡️</div>
                            <h5>实战阶段</h5>
                            <p>CTF 竞赛<br>漏洞赏金<br>安全审计</p>
                        </div>
                    </div>
                    <div class="warn-box">
                        ⚠️ 免责声明:本课程内容仅供安全研究与学习使用,请在法律允许范围内合理使用逆向技术。
                    </div>
                </div>
            </div>
        </div>

    </div>
</div>

<!-- 底部 dots -->
<div class="dots-bar" id="dotsBar"></div>
<div class="key-hint">← → 键切换页面</div>

<script>
let cur = 0;
const TOTAL = 8;
const slides = document.querySelectorAll('.slide');

const dotsBar = document.getElementById('dotsBar');
for (let i = 0; i < TOTAL; i++) {
    const d = document.createElement('div');
    d.className = 'dot' + (i === 0 ? ' active' : '');
    d.onclick = () => jump(i);
    dotsBar.appendChild(d);
}

function jump(idx) {
    if (idx === cur || idx < 0 || idx >= TOTAL) return;
    slides[cur].classList.remove('active');
    slides[cur].classList.add('exit-left');
    const prev = cur;
    setTimeout(() => slides[prev].classList.remove('exit-left'), 450);
    cur = idx;
    slides[cur].classList.add('active');
    updateUI();
}

function go(d) { jump(cur + d); }

function updateUI() {
    document.getElementById('counter').textContent = `${cur + 1} / ${TOTAL}`;
    document.getElementById('prog').style.width = `${((cur + 1) / TOTAL) * 100}%`;
    document.getElementById('btnPrev').disabled = cur === 0;
    document.getElementById('btnNext').disabled = cur === TOTAL - 1;
    document.querySelectorAll('.dot').forEach((d, i) => {
        d.className = 'dot' + (i === cur ? ' active' : '');
    });
}

document.addEventListener('keydown', e => {
    if (e.key === 'ArrowRight' || e.key === 'ArrowDown') go(1);
    if (e.key === 'ArrowLeft' || e.key === 'ArrowUp') go(-1);
});

let tx = 0;
document.addEventListener('touchstart', e => tx = e.touches[0].clientX);
document.addEventListener('touchend', e => {
    const d = tx - e.changedTouches[0].clientX;
    if (Math.abs(d) > 50) go(d > 0 ? 1 : -1);
});

function showToast(msg, type = 'info', dur = 3000) {
    const t = document.getElementById('toast');
    t.textContent = msg;
    t.className = `toast ${type} show`;
    clearTimeout(t._timer);
    t._timer = setTimeout(() => t.classList.remove('show'), dur);
}

function loadScript(src) {
    return new Promise((resolve, reject) => {
        if (window.PptxGenJS) { resolve(); return; }
        const s = document.createElement('script');
        s.src = src;
        s.onload = resolve;
        s.onerror = reject;
        document.head.appendChild(s);
    });
}

const CDN_URLS = ['https://unpkg.com/pptxgenjs@4.0.1/dist/pptxgen.bundle.js'];

async function ensurePptxGen() {
    if (window.PptxGenJS) return true;
    for (const url of CDN_URLS) {
        try {
            showToast('⏳ 正在加载导出库...', 'info', 10000);
            await loadScript(url);
            if (window.PptxGenJS) return true;
        } catch (e) { console.warn('CDN failed:', url, e); }
    }
    return false;
}

async function doExport() {
    const btn = document.getElementById('btnExport');
    btn.disabled = true;
    btn.textContent = '⏳ 生成中...';

    const ok = await ensurePptxGen();
    if (!ok) {
        showToast('❌ 库加载失败,请检查网络后重试', 'error', 5000);
        btn.disabled = false;
        btn.textContent = '📥 导出 PPTX';
        return;
    }

    showToast('⏳ 正在生成 PPTX,请稍候...', 'info', 15000);

    try {
        const pptx = new PptxGenJS();
        pptx.layout = 'LAYOUT_WIDE';
        pptx.title = '安卓逆向工程简介';

        const W = 13.33, H = 7.5;
        const C = {
            blue: '1a6bff', white: 'FFFFFF', dark: '1a1a1a',
            gray: '888888', light: 'f7f9fc', border: 'e8ecf2',
            lightBlue: 'edf2ff', red: 'e03030', green: '0a8040'
        };

        const addWhiteBg = (s) => s.addShape(pptx.ShapeType.rect, { x:0, y:0, w:W, h:H, fill:{color:C.white} });
        const sLabel = (s, txt, y=0.22) => s.addText(txt, { x:0.42, y, w:9, h:0.26, fontSize:9, bold:true, color:C.blue, charSpacing:2.5 });
        const sTitle = (s, parts, y=0.52) => s.addText(parts, { x:0.42, y, w:9, h:0.6, fontSize:22, bold:true });

        // Slide 1 封面
        {
            const s = pptx.addSlide();
            addWhiteBg(s);
            // 左侧蓝色区域
            s.addShape(pptx.ShapeType.rect, { x:0, y:0, w:7.0, h:H, fill:{color:C.blue} });
            // 装饰圆
            s.addShape(pptx.ShapeType.ellipse, { x:5.2, y:4.8, w:3.5, h:3.5, fill:{color:'1558d6'}, line:{color:'1558d6'} });
            s.addShape(pptx.ShapeType.ellipse, { x:-1.2, y:-1.0, w:2.5, h:2.5, fill:{color:'1558d6'}, line:{color:'1558d6'} });

            s.addShape(pptx.ShapeType.roundRect, { x:0.55, y:1.4, w:2.6, h:0.38, fill:{color:'ffffff22'}, line:{color:'ffffff44'}, rectRadius:0.15 });
            s.addText('● SECURITY RESEARCH', { x:0.55, y:1.4, w:2.6, h:0.38, align:'center', valign:'middle', fontSize:9.5, bold:true, color:C.white, charSpacing:1.5 });

            s.addText('安卓逆向工程', { x:0.5, y:2.0, w:6.2, h:1.0, fontSize:42, bold:true, color:C.white });
            s.addText('入门与实践简介', { x:0.5, y:3.08, w:6.2, h:0.65, fontSize:22, color:'ffffffcc' });
            s.addShape(pptx.ShapeType.rect, { x:0.5, y:3.88, w:0.55, h:0.04, fill:{color:'ffffff88'} });
            s.addText('Android Reverse Engineering · Introduction', { x:0.5, y:4.05, w:6.2, h:0.36, fontSize:11, color:'ffffff88', italic:true });

            // 右侧内容
            s.addText('课程涵盖内容', { x:7.3, y:1.25, w:5.7, h:0.36, fontSize:11, bold:true, color:C.blue, charSpacing:2 });

            const items = [
                ['📦', 'APK 安装包分析与解包技术'],
                ['🔍', '静态代码反编译与阅读'],
                ['🐛', '动态调试与运行时插桩'],
                ['🛡️', '安全研究与防护对抗'],
                ['⚙️', 'Frida Hook 实战应用'],
            ];
            items.forEach(([ic, txt], i) => {
                const y = 1.75 + i * 1.0;
                s.addShape(pptx.ShapeType.roundRect, { x:7.3, y, w:5.7, h:0.78, fill:{color:C.light}, line:{color:C.border}, rectRadius:0.08 });
                s.addShape(pptx.ShapeType.roundRect, { x:7.45, y:y+0.14, w:0.5, h:0.5, fill:{color:C.blue}, line:{color:C.blue}, rectRadius:0.07 });
                s.addText(ic, { x:7.45, y:y+0.14, w:0.5, h:0.5, align:'center', valign:'middle', fontSize:16 });
                s.addText(txt, { x:8.08, y:y+0.22, w:4.8, h:0.34, fontSize:12, color:C.dark });
            });
        }

        // Slide 2 目录
        {
            const s = pptx.addSlide();
            addWhiteBg(s);
            s.addShape(pptx.ShapeType.rect, { x:0, y:0, w:3.2, h:H, fill:{color:C.blue} });
            s.addShape(pptx.ShapeType.rect, { x:3.2, y:0, w:0.02, h:H, fill:{color:C.border} });

            s.addText('CONTENTS', { x:0.35, y:2.0, w:2.5, h:0.3, fontSize:9.5, bold:true, color:'ffffffaa', charSpacing:3 });
            s.addText('课程\n目录', { x:0.35, y:2.38, w:2.5, h:1.5, fontSize:30, bold:true, color:C.white, lineSpacingMultiple:1.1 });
            s.addShape(pptx.ShapeType.rect, { x:0.35, y:3.96, w:0.5, h:0.04, fill:{color:'ffffff66'} });

            const rows = [
                ['01','什么是安卓逆向','概念定义与应用场景'],
                ['02','核心工具链','必备工具与环境搭建'],
                ['03','APK 文件结构','深入了解安装包组成'],
                ['04','常用逆向技术','静态 / 动态分析方法'],
                ['05','防护与反制措施','加固方案 vs 绕过技术'],
                ['06','总结与学习路线','进阶方向与资源推荐'],
            ];
            rows.forEach(([n,t,d], i) => {
                const y = 0.6 + i * 1.02;
                s.addShape(pptx.ShapeType.roundRect, { x:3.4, y, w:9.6, h:0.8, fill:{color:C.light}, line:{color:C.border}, rectRadius:0.08 });
                s.addShape(pptx.ShapeType.roundRect, { x:3.56, y:y+0.15, w:0.5, h:0.5, fill:{color:C.blue}, line:{color:C.blue}, rectRadius:0.07 });
                s.addText(n, { x:3.56, y:y+0.15, w:0.5, h:0.5, align:'center', valign:'middle', fontSize:11, bold:true, color:C.white });
                s.addText(t, { x:4.2, y:y+0.1, w:7.5, h:0.32, fontSize:13, bold:true, color:C.dark });
                s.addText(d, { x:4.2, y:y+0.44, w:7.5, h:0.26, fontSize:10.5, color:C.gray });
                s.addText('', { x:12.5, y:y+0.2, w:0.4, h:0.4, align:'center', fontSize:16, bold:true, color:C.blue });
            });
        }

        // Slide 3 什么是逆向
        {
            const s = pptx.addSlide();
            addWhiteBg(s);
            s.addShape(pptx.ShapeType.rect, { x:0, y:0, w:W, h:0.04, fill:{color:C.blue} });
            sLabel(s, '01  ·  INTRODUCTION');
            sTitle(s, [{text:'什么是',options:{color:C.dark}},{text:'安卓逆向',options:{color:C.blue}},{text:'工程?',options:{color:C.dark}}]);

            s.addShape(pptx.ShapeType.rect, { x:0.42, y:1.26, w:0.06, h:0.88, fill:{color:C.blue} });
            s.addShape(pptx.ShapeType.roundRect, { x:0.58, y:1.26, w:7.4, h:0.88, fill:{color:'edf2ff'}, line:{color:'b8d0ff'}, rectRadius:0.06 });
            s.addText('安卓逆向工程是指在不具备源码的情况下,通过对 APK 文件进行反编译、分析和调试,\n理解应用程序的内部逻辑、数据流程和安全机制的技术手段。', { x:0.72, y:1.33, w:7.18, h:0.74, fontSize:11.5, color:'334466', lineSpacingMultiple:1.45 });

            const pts = [
                [C.blue,'漏洞挖掘:','发现 App 中的安全漏洞与隐私泄露风险'],
                [C.blue,'恶意分析:','分析病毒、木马等恶意程序的行为特征'],
                [C.blue,'兼容适配:','理解第三方 SDK 行为,辅助兼容性开发'],
                [C.blue,'安全审计:','对自身产品进行渗透测试与合规检测'],
                ['e06800','重要提示:','仅限合法授权范围内使用,切勿违法'],
            ];
            pts.forEach(([dc,t,d], i) => {
                s.addShape(pptx.ShapeType.ellipse, { x:0.45, y:2.35+i*0.55, w:0.1, h:0.1, fill:{color:dc} });
                s.addText([{text:t,options:{bold:true,color:C.dark,fontSize:12}},{text:'  '+d,options:{color:C.gray,fontSize:12}}], { x:0.65, y:2.3+i*0.55, w:7.3, h:0.44 });
            });

            // 右侧流程
            const flows = [['📦','APK 安装包','目标文件'],['🔧','反编译/解包','工具处理'],['🔍','静态分析','代码阅读'],['🐛','动态调试','运行监控'],['💡','分析结论','漏洞/算法']];
            flows.forEach(([ic,t,d], i) => {
                const isLast = i === 4;
                s.addShape(pptx.ShapeType.roundRect, { x:8.55, y:0.65+i*1.32, w:4.5, h:0.9, fill:{color:isLast?C.lightBlue:C.light}, line:{color:isLast?C.blue:C.border}, rectRadius:0.1 });
                s.addText(ic, { x:8.65, y:0.65+i*1.32, w:0.7, h:0.9, fontSize:20, align:'center', valign:'middle' });
                s.addText(t, { x:9.42, y:0.73+i*1.32, w:3.5, h:0.3, fontSize:12.5, bold:true, color:C.dark });
                s.addText(d, { x:9.42, y:1.06+i*1.32, w:3.5, h:0.26, fontSize:10, color:C.gray });
                if (i < 4) s.addText('', { x:8.55, y:1.5+i*1.32, w:4.5, h:0.38, align:'center', fontSize:14, color:C.blue });
            });
        }

        // Slide 4 工具链
        {
            const s = pptx.addSlide();
            addWhiteBg(s);
            s.addShape(pptx.ShapeType.rect, { x:0, y:0, w:W, h:0.04, fill:{color:C.blue} });
            sLabel(s, '02  ·  TOOLS');
            sTitle(s, [{text:'核心',options:{color:C.dark}},{text:'工具链',options:{color:C.blue}},{text:'全景',options:{color:C.dark}}]);

            const tools = [
                {ic:'🔨',n:'Jadx',tp:'反编译工具',desc:'将 DEX/APK 反编译为可读的 Java 源码,支持图形界面,是最常用的静态分析工具。',tags:['静态','Java','开源'],bg:'e8f0ff'},
                {ic:'📋',n:'Apktool',tp:'资源解包工具',desc:'反编译 APK 为 Smali 中间代码,支持修改后重新打包,常用于代码插桩与修改。',tags:['Smali','重打包','资源'],bg:'f0ebff'},
                {ic:'🐛',n:'Frida',tp:'动态插桩框架',desc:'可在运行时 Hook Java/Native 函数,拦截参数与返回值的强大动态分析工具。',tags:['动态','Hook','Python'],bg:'fff2e8'},
                {ic:'🌐',n:'Burp Suite',tp:'流量抓包工具',desc:'中间人代理工具,拦截分析 HTTP/HTTPS 流量,配合 SSL Unpinning 完成接口分析。',tags:['抓包','HTTPS','API'],bg:'eafaf0'},
                {ic:'🏔️',n:'IDA Pro',tp:'反汇编分析器',desc:'业界顶级反汇编工具,支持 ARM/x86 架构,用于深度分析 Native .so 库文件。',tags:['NDK','ARM','汇编'],bg:'fff0f0'},
                {ic:'📱',n:'ADB + Logcat',tp:'调试桥接工具',desc:'Android 调试桥,支持安装应用、查看日志、文件传输、Shell 命令执行等操作。',tags:['官方','日志','Shell'],bg:'e8f5ff'},
            ];

            const cw=4.15, ch=2.42, sx=0.36, sy=1.28, gx=0.19, gy=0.14;
            tools.forEach((t, i) => {
                const c=i%3, r=Math.floor(i/3);
                const x=sx+c*(cw+gx), y=sy+r*(ch+gy);
                s.addShape(pptx.ShapeType.roundRect, { x, y, w:cw, h:ch, fill:{color:C.light}, line:{color:C.border}, rectRadius:0.1 });
                s.addShape(pptx.ShapeType.roundRect, { x:x+0.14, y:y+0.18, w:0.6, h:0.6, fill:{color:t.bg}, line:{color:t.bg}, rectRadius:0.08 });
                s.addText(t.ic, { x:x+0.14, y:y+0.18, w:0.6, h:0.6, align:'center', valign:'middle', fontSize:20 });
                s.addText(t.n, { x:x+0.85, y:y+0.18, w:3.2, h:0.34, fontSize:13.5, bold:true, color:C.dark });
                s.addText(t.tp, { x:x+0.85, y:y+0.54, w:3.2, h:0.26, fontSize:9.5, color:C.gray });
                s.addText(t.desc, { x:x+0.14, y:y+0.92, w:cw-0.28, h:0.88, fontSize:10.5, color:C.gray, lineSpacingMultiple:1.4 });
                t.tags.forEach((tg,ti) => {
                    s.addShape(pptx.ShapeType.roundRect, { x:x+0.14+ti*1.27, y:y+1.95, w:1.15, h:0.3, fill:{color:C.lightBlue}, line:{color:'b8d0ff'}, rectRadius:0.05 });
                    s.addText(tg, { x:x+0.14+ti*1.27, y:y+1.95, w:1.15, h:0.3, align:'center', valign:'middle', fontSize:9.5, bold:true, color:C.blue });
                });
            });
        }

        // Slide 5 APK结构
        {
            const s = pptx.addSlide();
            addWhiteBg(s);
            s.addShape(pptx.ShapeType.rect, { x:0, y:0, w:W, h:0.04, fill:{color:C.blue} });
            sLabel(s, '03  ·  STRUCTURE');
            sTitle(s, [{text:'APK ',options:{color:C.dark}},{text:'文件结构',options:{color:C.blue}},{text:'解析',options:{color:C.dark}}]);

            s.addShape(pptx.ShapeType.roundRect, { x:0.36, y:1.24, w:7.6, h:6.0, fill:{color:'1a1a2a'}, line:{color:'1a1a2a'}, rectRadius:0.1 });

            const lines = [
                {t:'📦 example.apk  (ZIP 格式)',c:'5bb8ff',bold:true},
                {t:'├── 📄 classes.dex         ← Dalvik 字节码',c:'f0c040'},
                {t:'├── 📄 classes2.dex        ← 多 DEX 支持',c:'7b9cff'},
                {t:'├── 📄 AndroidManifest.xml',c:'f0c040'},
                {t:'├── 📁 res/                      ← 资源文件',c:'888888'},
                {t:'│    ├── layout/',c:'666666'},
                {t:'│    └── drawable/',c:'666666'},
                {t:'├── 📄 resources.arsc    ← 资源索引表',c:'4caf50'},
                {t:'├── 📁 assets/                ← 原始资源',c:'7b9cff'},
                {t:'├── 📁 lib/                      ← Native 库',c:'f0c040'},
                {t:'│    ├── arm64-v8a/',c:'666666'},
                {t:'│    └── armeabi-v7a/',c:'666666'},
                {t:'└── 📁 META-INF/          ← 签名信息',c:'4caf50'},
            ];
            lines.forEach((l,i) => {
                s.addText(l.t, { x:0.55, y:1.42+i*0.37, w:7.3, h:0.33, fontSize:10.5, fontFace:'Courier New', color:l.c, bold:!!l.bold });
            });

            const sc = [
                {t:'📄 classes.dex',d:'Dalvik 可执行文件,包含所有 Java/Kotlin 编译后的字节码,是逆向的核心目标。',c:C.blue},
                {t:'📄 AndroidManifest',d:'应用配置清单,包含权限申请、组件注册、版本信息等关键配置。',c:'7b2ff7'},
                {t:'📁 lib/',d:'Native C/C++ 编译的 .so 动态链接库,常含核心算法和加密逻辑。',c:'e06800'},
                {t:'📁 META-INF/',d:'存储 APK 签名文件(CERT.RSA),用于验证应用完整性与来源。',c:C.green},
                {t:'📁 assets/',d:'原始资源文件,可能存放加密配置或二次加密的 DEX 文件。',c:'999999'},
            ];
            sc.forEach((c,i) => {
                const y=1.24+i*1.24;
                s.addShape(pptx.ShapeType.roundRect, { x:8.2, y, w:4.82, h:1.08, fill:{color:C.light}, line:{color:C.border}, rectRadius:0.08 });
                s.addShape(pptx.ShapeType.rect, { x:8.2, y, w:0.05, h:1.08, fill:{color:c.c} });
                s.addText(c.t, { x:8.35, y:y+0.1, w:4.55, h:0.3, fontSize:12, bold:true, color:c.c });
                s.addText(c.d, { x:8.35, y:y+0.44, w:4.55, h:0.56, fontSize:10.5, color:C.gray, lineSpacingMultiple:1.3 });
            });
        }

        // Slide 6 常用技术
        {
            const s = pptx.addSlide();
            addWhiteBg(s);
            s.addShape(pptx.ShapeType.rect, { x:0, y:0, w:W, h:0.04, fill:{color:C.blue} });
            sLabel(s, '04  ·  TECHNIQUES');
            sTitle(s, [{text:'常用',options:{color:C.dark}},{text:'逆向技术',options:{color:C.blue}},{text:'总览',options:{color:C.dark}}]);

            const techs = [
                {ic:'🔍',t:'静态代码分析',d:'使用 Jadx 将 DEX 反编译为 Java 代码,分析业务逻辑、加密算法、API 接口。无需运行程序,风险低。',bg:'e8f0ff'},
                {ic:'🐛',t:'动态调试与插桩',d:'通过 Frida / Xposed 在运行时 Hook 关键函数,实时获取参数、返回值,追踪代码执行流。',bg:'f0ebff'},
                {ic:'✏️',t:'Smali 代码插桩',d:'使用 Apktool 解包为 Smali,手动修改字节码逻辑后重新打包签名,绕过限制或添加调试代码。',bg:'fff2e8'},
                {ic:'🌐',t:'网络流量分析',d:'使用 Burp Suite 代理拦截 HTTP/HTTPS 流量,配合 SSL Unpinning 绕过证书校验,还原接口协议。',bg:'eafaf0'},
                {ic:'💾',t:'内存 Dump 分析',d:'对运行中的进程进行内存转储,提取解密后的 DEX、密钥、敏感数据,突破加固保护层。',bg:'fff0f0'},
                {ic:'🏔️',t:'Native 层分析',d:'使用 IDA Pro / Ghidra 分析 .so 汇编代码,还原 Native 加密函数与核心算法逻辑。',bg:'e8f5ff'},
            ];

            const cw=6.3, ch=1.7, sx=0.36, sy=1.26, gx=0.25, gy=0.15;
            techs.forEach((tc,i) => {
                const c=i%2, r=Math.floor(i/2);
                const x=sx+c*(cw+gx), y=sy+r*(ch+gy);
                s.addShape(pptx.ShapeType.roundRect, { x, y, w:cw, h:ch, fill:{color:C.light}, line:{color:C.border}, rectRadius:0.1 });
                s.addShape(pptx.ShapeType.roundRect, { x:x+0.15, y:y+0.2, w:0.68, h:0.68, fill:{color:tc.bg}, line:{color:tc.bg}, rectRadius:0.08 });
                s.addText(tc.ic, { x:x+0.15, y:y+0.2, w:0.68, h:0.68, align:'center', valign:'middle', fontSize:20 });
                s.addText(tc.t, { x:x+0.96, y:y+0.22, w:cw-1.1, h:0.36, fontSize:13.5, bold:true, color:C.dark });
                s.addText(tc.d, { x:x+0.96, y:y+0.6, w:cw-1.1, h:1.0, fontSize:11, color:C.gray, lineSpacingMultiple:1.4 });
            });
        }

        // Slide 7 防护与反制
        {
            const s = pptx.addSlide();
            addWhiteBg(s);
            s.addShape(pptx.ShapeType.rect, { x:0, y:0, w:W, h:0.04, fill:{color:C.blue} });
            sLabel(s, '05  ·  DEFENSE & ATTACK');
            s.addText([
                {text:'防护',options:{color:C.dark}},
                {text:'加固',options:{color:C.blue}},
                {text:' vs 逆向',options:{color:C.dark}},
                {text:'反制',options:{color:C.red}}
            ], { x:0.42, y:0.52, w:9, h:0.6, fontSize:22, bold:true });

            s.addShape(pptx.ShapeType.rect, { x:0, y:1.26, w:W, h:0.02, fill:{color:C.border} });

            // 左列
            const atks = [
                ['🔓','反调试绕过','Hook ptrace / TracerPid 检测,欺骗反调试校验逻辑'],
                ['📡','SSL Pinning 绕过','Frida Hook 证书验证函数,实现中间人流量抓包'],
                ['💉','内存 Dump 脱壳','在 DEX 加载完毕后从内存中提取原始代码文件'],
                ['🔄','模拟器环境伪装','修改设备指纹参数绕过模拟器检测逻辑'],
                ['✏️','重打包签名伪造','修改 Smali 代码后重新打包,绕过签名校验'],
            ];
            s.addShape(pptx.ShapeType.roundRect, { x:0.36, y:1.36, w:6.05, h:0.54, fill:{color:'fff0f0'}, line:{color:'ffbbbb'}, rectRadius:0.08 });
            s.addText('🔥  逆向 / 攻击手段', { x:0.36, y:1.36, w:6.05, h:0.54, align:'center', valign:'middle', fontSize:13.5, bold:true, color:C.red });
            atks.forEach(([ic,t,d],i) => {
                const y=2.06+i*1.0;
                s.addShape(pptx.ShapeType.roundRect, { x:0.36, y, w:6.05, h:0.84, fill:{color:C.light}, line:{color:C.border}, rectRadius:0.08 });
                s.addText(ic, { x:0.48, y:y+0.1, w:0.52, h:0.6, align:'center', fontSize:18 });
                s.addText(t, { x:1.08, y:y+0.1, w:5.2, h:0.3, fontSize:12.5, bold:true, color:C.dark });
                s.addText(d, { x:1.08, y:y+0.44, w:5.2, h:0.3, fontSize:10.5, color:C.gray });
            });

            s.addShape(pptx.ShapeType.line, { x:6.67, y:1.3, w:0, h:6.0, line:{color:C.border, width:1} });
            s.addShape(pptx.ShapeType.roundRect, { x:6.46, y:3.8, w:0.44, h:0.44, fill:{color:C.white}, line:{color:C.border}, rectRadius:0.12 });
            s.addText('VS', { x:6.46, y:3.8, w:0.44, h:0.44, align:'center', valign:'middle', fontSize:10, bold:true, color:'bbbbbb' });

            // 右列
            const prts = [
                ['🔐','代码混淆','ProGuard/R8 混淆类名、方法名,增加阅读难度'],
                ['📦','DEX 加壳加固','梆梆、360加固等方案加密 DEX,运行时解密加载'],
                ['🔍','反调试检测','检测 TracerPid、Frida 特征值、调试端口占用'],
                ['','签名完整性校验','运行时验证 APK 签名哈希,防止重打包篡改'],
                ['📌','SSL Certificate Pinning','内置服务器证书指纹,防止流量中间人攻击'],
            ];
            s.addShape(pptx.ShapeType.roundRect, { x:6.94, y:1.36, w:6.05, h:0.54, fill:{color:C.lightBlue}, line:{color:'b8d0ff'}, rectRadius:0.08 });
            s.addText('🛡️  防护 / 加固手段', { x:6.94, y:1.36, w:6.05, h:0.54, align:'center', valign:'middle', fontSize:13.5, bold:true, color:C.blue });
            prts.forEach(([ic,t,d],i) => {
                const y=2.06+i*1.0;
                s.addShape(pptx.ShapeType.roundRect, { x:6.94, y, w:6.05, h:0.84, fill:{color:C.light}, line:{color:C.border}, rectRadius:0.08 });
                s.addText(ic, { x:7.06, y:y+0.1, w:0.52, h:0.6, align:'center', fontSize:18 });
                s.addText(t, { x:7.66, y:y+0.1, w:5.2, h:0.3, fontSize:12.5, bold:true, color:C.dark });
                s.addText(d, { x:7.66, y:y+0.44, w:5.2, h:0.3, fontSize:10.5, color:C.gray });
            });
        }

        // Slide 8 总结
        {
            const s = pptx.addSlide();
            addWhiteBg(s);
            s.addShape(pptx.ShapeType.rect, { x:0, y:0, w:W, h:3.1, fill:{color:C.blue} });
            s.addShape(pptx.ShapeType.ellipse, { x:10.0, y:-1.2, w:3.5, h:3.5, fill:{color:'1558d6'}, line:{color:'1558d6'} });
            s.addShape(pptx.ShapeType.ellipse, { x:-0.8, y:1.2, w:2.5, h:2.5, fill:{color:'1558d6'}, line:{color:'1558d6'} });

            s.addText('🎯', { x:0, y:0.35, w:W, h:0.8, align:'center', fontSize:34 });
            s.addText('总结与学习路线', { x:0.5, y:1.25, w:W-1, h:0.7, align:'center', fontSize:28, bold:true, color:C.white });
            s.addText('安卓逆向是一门综合性极强的技术,涵盖 Java/Smali/ARM 汇编、网络协议、密码学等多个领域。\n建议从基础工具入手,循序渐进,逐步深入 Native 层分析与协议还原。', {
                x:1.5, y:2.05, w:W-3, h:0.85, align:'center', fontSize:12, color:'ffffffbb', lineSpacingMultiple:1.6
            });

            const stages = [
                {ic:'📚',t:'基础阶段',d:'Java/Kotlin\nADB 调试\nJadx 使用'},
                {ic:'🔧',t:'进阶阶段',d:'Frida Hook\nSmali 分析\nBurp 抓包'},
                {ic:'🏔️',t:'高级阶段',d:'IDA Pro\n脱壳技术\n协议还原'},
                {ic:'🛡️',t:'实战阶段',d:'CTF 竞赛\n漏洞赏金\n安全审计'},
            ];
            stages.forEach((st,i) => {
                const x=0.72+i*3.15;
                s.addShape(pptx.ShapeType.roundRect, { x, y:3.28, w:2.9, h:2.55, fill:{color:C.light}, line:{color:C.border}, rectRadius:0.12 });
                s.addText(st.ic, { x, y:3.42, w:2.9, h:0.6, align:'center', fontSize:22 });
                s.addText(st.t, { x, y:4.08, w:2.9, h:0.36, align:'center', fontSize:13, bold:true, color:C.dark });
                s.addText(st.d, { x, y:4.48, w:2.9, h:1.2, align:'center', fontSize:11.5, color:C.gray, lineSpacingMultiple:1.55 });
            });

            s.addShape(pptx.ShapeType.roundRect, { x:0.72, y:6.06, w:W-1.44, h:0.72, fill:{color:'fffbec'}, line:{color:'f0d060'}, rectRadius:0.08 });
            s.addText('⚠️  免责声明:本课程内容仅供安全研究与学习使用,请在法律允许的范围内合理使用逆向技术,切勿违法。', {
                x:0.72, y:6.06, w:W-1.44, h:0.72, align:'center', valign:'middle', fontSize:11.5, color:'886600'
            });
        }

        await pptx.writeFile({ fileName: '安卓逆向工程简介.pptx' });
        showToast('✅ PPTX 导出成功!', 'success', 4000);
    } catch (err) {
        console.error(err);
        showToast('❌ 生成失败:' + err.message, 'error', 5000);
    } finally {
        btn.disabled = false;
        btn.innerHTML = '📥 导出 PPTX';
    }
}
</script>
</body>
</html>

 

 

 

苹果风 AI提示词

# 角色
你是一位资深的 PPT 设计师 + 前端工程师,擅长 Apple 风格极简设计和 pptxgenjs 库。

# 任务
生成一个**单文件 HTML**,主题是「{{在此填写主题}}」,共 {{N}} 页幻灯片。
该 HTML 在浏览器中是一个交互式 PPT 预览器,并且带有一键「导出 PPTX」按钮,点击后通过 pptxgenjs 生成一份**视觉上与 HTML 完全一致的 .pptx 文件**。

# 一、整体架构(必须严格遵守)
1. **单个 .html 文件**,内联 CSS + JS,零外部依赖(pptxgenjs 在点击导出时动态 CDN 加载:`https://unpkg.com/pptxgenjs@4.0.1/dist/pptxgen.bundle.js`)。
2. 页面布局三区:
   - **顶部固定栏**(高52px,毛玻璃 `backdrop-filter: blur(20px)`):左侧 app 图标+标题,中间「← 页码 →」导航,右侧黑色「↓ 导出 PPTX」按钮。
   - **左侧缩略图栏**(宽180px,毛玻璃):由 JS 根据 `slidesData` 数组动态生成,包含页码、标题、副标题,点击可跳转,当前页高亮。
   - **主内容区**:单张 `.slide` 容器,`aspect-ratio:16/9`,`max-width:960px`,白底、圆角16px、柔和阴影;通过 `.active` 类切换显示。
3. 交互:左右方向键翻页、点击缩略图跳转、点击进度点跳转,切换有 `slideIn` 淡入动画。
4. 导出加载遮罩:点击导出时显示「正在生成 PPTX 文件」loading 层。

# 二、视觉设计系统(Apple 极简风)
- **调色板**(HTML 与 PPTX 必须同色):
  ```
  黑 #1d1d1f | 灰 #6e6e73 | 浅灰背景 #f5f5f7 | 边框 #d2d2d7 | 白 #ffffff
  ```
- **字体**:`-apple-system, BlinkMacSystemFont, 'SF Pro Display', 'Helvetica Neue', Arial`;PPTX 中用 `Arial`,代码用 `Courier New`。
- **字号规范**:主标题 46-52px、章节标题 28px、卡片标题 12-14px、正文 10-12px、页脚 8-9px。
- **元素规范**- 每页左边缘 0.06"宽纯黑装饰竖条
  - 章节标签用大写英文「CHAPTER 0X」+ 字距 1px,下方一条 40px 黑色 `accent-line`
  - 卡片统一 `border-radius: 12-16px`、浅灰背景 `#f5f5f7`、1px 细边框
  - 首页可用毛玻璃 `.glass-card` 作右侧视觉元素(代码块 / 图示卡)
  - 页脚统一:左「ANDROID REVERSE」品牌字 + 中间细线 + 右「0X / XX」页码

# 三、HTML 页面结构(关键类名保持一致)
```
.top-bar / .sidebar .thumb-item / .slide-wrapper > .slide.slide-N
每张 .slide 内:.slide-content > .section-header (.section-label + .accent-line + .section-title) + 主体区 + .slide-footer
```
- 布局模式可选:**首页左右分栏**、**two-col 双列卡片**、**tool-list 列表**、**5步时间线(圆圈+连接线)**、**三/四列卡片网格**、**数据统计大数字**- JS 中维护 `slidesData = [{num, title, subtitle}, ...]` 用于生成缩略图。

# 四、PPTX 导出(核心 —— 必须逐页 1:1 还原)
```js
const pptx = new PptxGenJS();
pptx.layout = 'LAYOUT_WIDE';  // 13.33 x 7.5 英寸 16:9
pptx.author/company/subject/title = '...';
const C = { black:'1d1d1f', gray:'6e6e73', lightGray:'f5f5f7', border:'d2d2d7', white:'ffffff' };
```
**每一页都用独立 `{ ... }` 块**构建,顺序复刻 HTML:
1. `slide.background = { color: C.white }`
2. 左边缘装饰条 `addShape(rect, {x:0,y:0,w:0.06,h:7.5, fill:{color:C.black}})`
3. `CHAPTER 0X` 标签 + 装饰短线 + 章节大标题
4. 卡片用 `addShape(roundRect, {... rectRadius:0.12, fill:{color:C.lightGray}, line:{color:'e8e8ed',width:1}})`,再在其上用 `addText` 叠加文字
5. 强调块用反色(黑底白字)
6. 图标用 Emoji 直接写在文字里(`🔧 通俗理解`)
7. 页脚品牌字 + 页码(`0.5" / 11.5"` 两端对齐)

**坐标单位为英寸**,常用基准:
- 页面 13.33" × 7.5"
- 左右留白 0.5"、内容宽度 12.3"
- 左右两栏:每栏 5.8" 宽,间距 0.4"
- 章节标题 y=0.95、主体区从 y=1.85 开始、页脚 y=7.0

# 五、内容要求
- {{N}} 页大纲由你根据主题自行合理设计,但需包含:封面页 + 章节页 + 总结/路线图页。
- 文案中文为主,数据/代码/术语用英文,保持信息密度适中,不堆砌。
- 所有可视化元素(图表、流程链、对比卡)在 HTML 和 PPTX 中都用**原生形状 + 文字**绘制,不引入图片。

# 六、交付
直接输出完整 `.html` 文件代码(一个代码块,无多余解释)。确保:
- 浏览器打开即可预览、键盘可翻页;
- 点击「导出 PPTX」成功下载 `{{主题}}.pptx`,打开后每一页视觉与 HTML 一致。

使用说明

下次只需把这段提示词发给 AI,并在以下位置填空:

  • {{在此填写主题}} → 例如:"React 19 新特性"、"区块链入门" 等
  • {{N}} → 页数,例如 10

AI 就能生成一份同款 Apple 极简风 + 可导出 PPTX 的 HTML 幻灯片文件。

 

商务风  AI 提示词

# 角色
你是资深的 PPT 设计师 + 前端工程师,精通 pptxgenjs 库,擅长「中国企业科技蓝」商务风幻灯片。

# 任务
生成**单个 .html 文件**,主题为「{{在此填写主题}}」,共 {{N}} 页。
该文件在浏览器中是交互式 PPT 预览器,点击右上角「📥 导出 PPTX」按钮,可通过 pptxgenjs 生成视觉上与 HTML **完全一致**的 .pptx 文件。

# 一、整体架构
1. **单文件 HTML**,内联 CSS + JS,零本地依赖;导出时才动态从 CDN 加载 `https://unpkg.com/pptxgenjs@4.0.1/dist/pptxgen.bundle.js`,并带 loadScript + ensurePptxGen 失败重试机制。
2. 页面结构:
   - **顶部控制栏** (`.control-bar`, 高54px, 白底):左侧 logo 圆角图标(品牌蓝背景) + 品牌名 + 胶囊状页码计数器 `1 / N`;右侧「◀上一页 / 下一页▶ / 📥导出 PPTX」三按钮。
   - **进度条** (`.progress`):顶栏下方 3px 蓝色横条,宽度随页码变化,0.4s 缓动。
   - **舞台区** (`.stage`):`max-width:1000px`,`aspect-ratio:16/9`,白底圆角12px + 柔和阴影;切换带 `translateX + scale + opacity` 缓动。
   - **底部 dots 栏** (`.dots-bar`, 高60px):圆点导航,当前页胶囊化(宽28px, 蓝色)。
   - **Toast 通知** (`.toast`):info/success/error 三色,右上角弹出(导出过程反馈)。
3. 交互:← → 方向键翻页、触摸滑动、点击圆点跳转。
4. **关键字体**:`'Microsoft YaHei', '微软雅黑', sans-serif`(中文商务风)。

# 二、视觉设计系统(科技蓝商务风)
- **主色板**(HTML 与 PPTX 必须同色号):
  ```
  主蓝 #1a6bff     深蓝 #1558d6      浅蓝 #edf2ff      浅蓝底 #e8f0ff
  深文字 #1a1a1a   次文字 #888888    浅灰底 #f7f9fc    边框 #e8ecf2
  强调红 #e03030   强调绿 #0a8040    强调橙 #e06800    警告黄底 #fffbec / 边#f0d060
  ```
- **字号规范**:封面主标 38-42px、章节标题 22-24px、卡片标题 12-14px、正文 10.5-12px、标签 9-10px (letter-spacing: 2-2.5px, uppercase)。
- **统一元素**- 每章节页顶部 4px 蓝色装饰横条
  - 章节小标签 `0X · ENGLISH`(蓝色、粗体、字距2.5px、大写)
  - 标题中可混排 `<span class="hl">蓝色强调词</span>`
  - 卡片统一:浅灰底 `#f7f9fc` + 1px 边框 `#e8ecf2` + 圆角 8-12px
  - 图标容器:彩色柔和底(如 #e8f0ff / #fff2e8 / #eafaf0)+ emoji 图标
  - 标签小胶囊:浅蓝底 + 蓝字 + 粗体

# 三、推荐页面模板(可按主题组合)
1. **封面页**:左右分栏,左侧大面积蓝色背景 + 装饰圆(`::before/::after`半透明白圆)+ 胶囊 badge + 巨型标题 + 分隔条 + 英文副标;右侧白色 + 5 个彩色图标标签项列表。
2. **目录页**:左侧 220px 蓝色竖栏(CONTENTS + "课程\n目录"大字)+ 右侧 6 行卡片列表(编号圆角块 + 标题 + 描述 + `›`箭头)。
3. **概念定义页**:左 `def-box`(浅蓝底定义框)+ 下方 5 条带圆点要点;右侧 5 步纵向流程卡片(含图标 + ↓箭头 + 最后一步高亮蓝边)。
4. **工具/技术矩阵页**:3×22×3 卡片网格,每卡 = 彩色图标 + 标题 + 类型副标 + 描述 + 3 个蓝色小标签。
5. **对比页(VS)**:左右两列,左红色表头 `🔥 攻击` + 右蓝色表头 `🛡️ 防护`,中间竖线 + VS 小徽章。
6. **代码/树形展示**:深色代码框 `#1a1a2a` + 彩色 Courier New 文本;右侧说明卡片(左边缘彩色竖条)。
7. **总结/路线图页**:顶部蓝色横幅 + 装饰圆 + 大图标 + 标题 + 描述;下方 4 个阶段卡片;底部黄色警示条(免责声明)。

# 四、PPTX 导出(核心:与 HTML 1:1 还原)
```js
const pptx = new PptxGenJS();
pptx.layout = 'LAYOUT_WIDE';   // 13.33 × 7.5 英寸 16:9
const W = 13.33, H = 7.5;
const C = { blue:'1a6bff', white:'FFFFFF', dark:'1a1a1a', gray:'888888',
            light:'f7f9fc', border:'e8ecf2', lightBlue:'edf2ff',
            red:'e03030', green:'0a8040' };

// 辅助函数(强烈建议提炼):
const addWhiteBg = (s) => s.addShape(pptx.ShapeType.rect, { x:0,y:0,w:W,h:H, fill:{color:C.white} });
const sLabel = (s, txt, y=0.22) => s.addText(txt, { x:0.42,y,w:9,h:0.26, fontSize:9, bold:true, color:C.blue, charSpacing:2.5 });
const sTitle = (s, parts, y=0.52) => s.addText(parts, { x:0.42,y,w:9,h:0.6, fontSize:22, bold:true });
```
每页用 `{ ... }` 块隔离作用域构建:
- **必备元素**:白底 + 顶部 4px 蓝装饰条 + `sLabel('0X · ENGLISH')` + `sTitle([{text,options:{color:C.dark}},{text,options:{color:C.blue}}, ...])` 混色标题。
- **卡片**:`addShape(roundRect, { fill:{color:C.light}, line:{color:C.border}, rectRadius:0.08~0.12 })` 再叠 `addText`。
- **图标容器**:彩色小圆角矩形 + emoji 居中 (`align:'center', valign:'middle', fontSize:16-22`)。
- **代码块**:深色圆角矩形 + `fontFace:'Courier New'` + 彩色字 (黄/蓝/绿/灰层级)。
- **装饰圆**:`addShape(ellipse, { ... fill:{color:'1558d6'} })` 置于角落制造科技感。
- **混色标题**:`s.addText([{text:'前缀',options:{color:C.dark}},{text:'关键词',options:{color:C.blue}},...], {...})`。

**布局基准**(英寸):
- 左右留白 0.36-0.42";内容主区 y=1.26-1.28" 起;标题在 y=0.22-0.52"
- 3×2 卡片网格:`cw=4.15, ch=2.42, gx=0.19, gy=0.14`
- 2×3 卡片网格:`cw=6.3, ch=1.7, gx=0.25, gy=0.15`

# 五、内容要求
- {{N}} 页合理大纲:**封面 → 目录 → 概念 → 工具/要素 → 结构/分类 → 方法/技术 → 对比 → 总结**- 中文为主,英文仅用于标签、代码、术语;信息密度适中。
- 所有图示(流程、对比、矩阵)在 HTML 和 PPTX 中均用**原生形状+文字**绘制,不引入图片资源。

# 六、交付要求
直接输出完整 `.html` 文件代码(单一代码块),确保:
- 浏览器打开可流畅预览、键盘/触摸可翻页;
- 点击「📥 导出 PPTX」→ Toast 提示「生成中」→ 成功下载 `{{主题}}.pptx`;
- PPTX 每一页的色彩、布局、文字、图标与 HTML 版本**视觉一致**。

 

[粘贴上面的提示词]
主题 = "K8s 容器编排入门" 
N = 10
即可得到一份同款商务蓝科技感的可导出 PPTX 幻灯片。
 
高级的提示词可以让deepseek也可以设计出高级的ui
因此有四种提示词
无任何限制词,有简单限制的提示词,详细定义风格的提示词,完全定义每个细节的提示词 
 
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>安卓VMP加固技术深度解析</title>
<style>
  *, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
  
  :root {
    --bg: #061529;
    --bg2: #0a1f3d;
    --border: #0e3a6e;
    --cyan: #00d4ff;
    --cyan2: #00a8cc;
    --white: #e8f4ff;
    --gray: #7ab0d4;
    --green: #00ff88;
    --orange: #ff8c00;
    --yellow: #ffd700;
    --dark: #1a4a8a;
  }

  body {
    background: #020d1a;
    font-family: 'Microsoft YaHei', '微软雅黑', sans-serif;
    color: var(--white);
    min-height: 100vh;
    display: flex;
    flex-direction: column;
    overflow: hidden;
    user-select: none;
  }

  /* ── 控制栏 ── */
  .control-bar {
    height: 54px;
    background: linear-gradient(90deg, #061529 0%, #0a1f3d 50%, #061529 100%);
    border-bottom: 1px solid var(--border);
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 0 20px;
    flex-shrink: 0;
    z-index: 100;
  }
  .bar-left { display: flex; align-items: center; gap: 14px; }
  .bar-logo {
    width: 32px; height: 32px;
    background: linear-gradient(135deg, #00d4ff, #0066cc);
    border-radius: 8px;
    display: flex; align-items: center; justify-content: center;
    font-size: 16px; font-weight: 900;
    box-shadow: 0 0 12px rgba(0,212,255,0.5);
  }
  .bar-brand { font-size: 14px; font-weight: 700; color: var(--white); letter-spacing: 1px; }
  .bar-page {
    background: rgba(0,212,255,0.15);
    border: 1px solid rgba(0,212,255,0.4);
    border-radius: 20px;
    padding: 3px 12px;
    font-size: 12px;
    color: var(--cyan);
    font-weight: 600;
  }
  .bar-right { display: flex; align-items: center; gap: 10px; }
  .btn {
    height: 32px; padding: 0 14px;
    border: 1px solid var(--border);
    background: rgba(10,31,61,0.8);
    color: var(--white);
    border-radius: 6px;
    cursor: pointer;
    font-size: 13px;
    font-family: 'Microsoft YaHei', sans-serif;
    transition: all .2s;
    display: flex; align-items: center; gap: 6px;
  }
  .btn:hover { background: rgba(0,212,255,0.15); border-color: var(--cyan); color: var(--cyan); }
  .btn-export {
    background: linear-gradient(135deg, rgba(0,212,255,0.2), rgba(0,102,204,0.3));
    border-color: var(--cyan);
    color: var(--cyan);
    font-weight: 700;
  }
  .btn-export:hover { background: linear-gradient(135deg, rgba(0,212,255,0.4), rgba(0,102,204,0.5)); box-shadow: 0 0 15px rgba(0,212,255,0.4); }

  /* ── 进度条 ── */
  .progress-wrap { height: 3px; background: rgba(14,58,110,0.5); flex-shrink: 0; }
  .progress-bar { height: 3px; background: linear-gradient(90deg, #00d4ff, #0066cc); transition: width .4s ease; box-shadow: 0 0 8px rgba(0,212,255,0.7); }

  /* ── 舞台区 ── */
  .stage-wrap {
    flex: 1;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 16px 20px 8px;
    overflow: hidden;
  }
  .stage {
    width: 100%;
    max-width: 1000px;
    aspect-ratio: 16/9;
    position: relative;
    border-radius: 12px;
    overflow: hidden;
    box-shadow: 0 0 40px rgba(0,212,255,0.2), 0 0 80px rgba(0,100,200,0.15), 0 20px 60px rgba(0,0,0,0.6);
    border: 1px solid rgba(0,212,255,0.15);
  }

  /* ── 幻灯片 ── */
  .slide {
    position: absolute; inset: 0;
    background: var(--bg);
    display: none;
    overflow: hidden;
  }
  .slide.active { display: block; animation: slideIn .4s ease; }
  .slide.exit { animation: slideOut .3s ease forwards; }

  @keyframes slideIn {
    from { transform: translateX(40px) scale(0.97); opacity: 0; }
    to   { transform: translateX(0) scale(1); opacity: 1; }
  }
  @keyframes slideOut {
    from { transform: translateX(0) scale(1); opacity: 1; }
    to   { transform: translateX(-40px) scale(0.97); opacity: 0; }
  }

  /* ── 圆点导航 ── */
  .dots-bar {
    height: 56px;
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 8px;
    flex-shrink: 0;
  }
  .dot {
    height: 8px; width: 8px;
    border-radius: 4px;
    background: rgba(0,212,255,0.25);
    border: 1px solid rgba(0,212,255,0.3);
    cursor: pointer;
    transition: all .3s;
  }
  .dot.active {
    width: 28px;
    background: var(--cyan);
    box-shadow: 0 0 10px rgba(0,212,255,0.7);
  }
  .dot:hover:not(.active) { background: rgba(0,212,255,0.5); }

  /* ── Toast ── */
  .toast {
    position: fixed;
    top: 70px; right: 20px;
    padding: 10px 18px;
    border-radius: 8px;
    font-size: 13px;
    font-weight: 600;
    z-index: 9999;
    transform: translateX(120%);
    transition: transform .3s ease;
    border: 1px solid;
    backdrop-filter: blur(10px);
  }
  .toast.show { transform: translateX(0); }
  .toast.info  { background: rgba(0,100,200,0.85); border-color: var(--cyan); color: var(--cyan); }
  .toast.success { background: rgba(0,100,60,0.85); border-color: var(--green); color: var(--green); }
  .toast.error { background: rgba(100,20,20,0.85); border-color: #ff4444; color: #ff6666; }

  /* ══════════════════════════════════
     通用幻灯片内部样式
  ══════════════════════════════════ */

  /* 顶部装饰条 */
  .s-topbar {
    position: absolute; top: 0; left: 0; right: 0;
    height: 4px;
    background: linear-gradient(90deg, #00d4ff 0%, #0066cc 60%, transparent 100%);
  }

  /* LOGO右上角 */
  .s-logo {
    position: absolute; top: 10px; right: 16px;
    font-size: 11px; font-weight: 700;
    color: var(--cyan);
    letter-spacing: 2px;
    opacity: 0.8;
  }

  /* 装饰大圆 */
  .s-circle {
    position: absolute;
    border-radius: 50%;
    background: radial-gradient(circle, rgba(26,74,138,0.6) 0%, transparent 70%);
    pointer-events: none;
  }

  /* 科技网格背景 */
  .s-grid {
    position: absolute; inset: 0;
    background-image:
      repeating-linear-gradient(0deg, transparent, transparent 39px, rgba(0,212,255,0.06) 39px, rgba(0,212,255,0.06) 40px),
      repeating-linear-gradient(90deg, transparent, transparent 39px, rgba(0,212,255,0.06) 39px, rgba(0,212,255,0.06) 40px);
    pointer-events: none;
  }

  /* 页码标签 */
  .s-label {
    position: absolute; top: 14px; left: 20px;
    font-size: 9px; font-weight: 700;
    color: var(--cyan);
    letter-spacing: 2.5px;
    text-transform: uppercase;
  }

  /* 标题区 */
  .s-title {
    position: absolute; top: 36px; left: 20px; right: 120px;
    font-size: 20px; font-weight: 700;
    color: var(--white);
    line-height: 1.3;
  }
  .s-title .hl { color: var(--cyan); text-shadow: 0 0 15px rgba(0,212,255,0.7); }

  /* 分隔线 */
  .s-divider {
    position: absolute;
    height: 1px;
    background: linear-gradient(90deg, var(--cyan), transparent);
    opacity: 0.4;
  }

  /* 卡片 */
  .s-card {
    position: absolute;
    background: var(--bg2);
    border: 1px solid var(--border);
    border-radius: 10px;
    box-shadow: 0 0 20px rgba(0,212,255,0.1), inset 0 1px 0 rgba(0,212,255,0.05);
    overflow: hidden;
  }
  .s-card::before {
    content: '';
    position: absolute; left: 0; top: 0; bottom: 0;
    width: 3px;
    background: var(--cyan);
  }
  .s-card.orange::before { background: var(--orange); }
  .s-card.green::before  { background: var(--green); }
  .s-card.yellow::before { background: var(--yellow); }

  /* 卡片内文字 */
  .card-title { font-size: 13px; font-weight: 700; color: var(--white); margin-bottom: 5px; }
  .card-sub   { font-size: 10px; color: var(--cyan); margin-bottom: 6px; text-transform: uppercase; letter-spacing: 1px; }
  .card-desc  { font-size: 10.5px; color: var(--gray); line-height: 1.55; }
  .card-tag {
    display: inline-block;
    background: rgba(0,212,255,0.12);
    border: 1px solid rgba(0,212,255,0.3);
    border-radius: 4px;
    padding: 2px 7px;
    font-size: 9px;
    color: var(--cyan);
    letter-spacing: 1px;
    margin-top: 5px;
  }
  .card-tag.orange { background: rgba(255,140,0,0.12); border-color: rgba(255,140,0,0.3); color: var(--orange); }
  .card-tag.green  { background: rgba(0,255,136,0.12); border-color: rgba(0,255,136,0.3);  color: var(--green);  }
  .card-tag.red    { background: rgba(255,60,60,0.12);  border-color: rgba(255,60,60,0.3);  color: #ff6666;       }

  /* 大数字 */
  .big-num {
    font-size: 42px; font-weight: 900;
    color: var(--yellow);
    text-shadow: 0 0 30px rgba(255,215,0,0.8);
    line-height: 1;
  }
  .big-num.cyan { color: var(--cyan); text-shadow: 0 0 30px rgba(0,212,255,0.8); }
  .big-num.green { color: var(--green); text-shadow: 0 0 30px rgba(0,255,136,0.8); }

  /* 胶囊badge */
  .badge {
    display: inline-block;
    padding: 3px 12px;
    border-radius: 20px;
    font-size: 10px;
    font-weight: 700;
    letter-spacing: 2px;
    text-transform: uppercase;
    border: 1px solid var(--cyan);
    color: var(--cyan);
    background: rgba(0,212,255,0.1);
  }

  /* 进度条 */
  .prog-track {
    background: rgba(26,58,92,0.8);
    border: 1px solid var(--border);
    border-radius: 4px;
    height: 10px;
    overflow: hidden;
  }
  .prog-fill {
    height: 100%;
    border-radius: 4px;
    background: linear-gradient(90deg, var(--cyan), #0066cc);
    box-shadow: 0 0 8px rgba(0,212,255,0.6);
    transition: width .8s ease;
  }

  /* 流程步骤箭头 */
  .flow-step {
    position: absolute;
    background: var(--bg2);
    border: 1px solid var(--border);
    border-radius: 8px;
    display: flex; flex-direction: column;
    align-items: center; justify-content: center;
    text-align: center;
    box-shadow: 0 0 15px rgba(0,212,255,0.1);
  }
  .flow-num {
    width: 24px; height: 24px;
    background: linear-gradient(135deg, var(--cyan), #0066cc);
    border-radius: 50%;
    display: flex; align-items: center; justify-content: center;
    font-size: 11px; font-weight: 900;
    color: #fff;
    margin-bottom: 6px;
    box-shadow: 0 0 10px rgba(0,212,255,0.5);
  }

  /* 图标圆框 */
  .icon-box {
    width: 36px; height: 36px;
    border-radius: 8px;
    display: flex; align-items: center; justify-content: center;
    font-size: 18px;
    flex-shrink: 0;
  }

  /* 时间轴 */
  .timeline-line {
    position: absolute;
    width: 2px;
    background: linear-gradient(180deg, var(--cyan), transparent);
    opacity: 0.5;
  }
  .timeline-dot {
    position: absolute;
    width: 10px; height: 10px;
    border-radius: 50%;
    background: var(--cyan);
    box-shadow: 0 0 10px rgba(0,212,255,0.8);
    left: -4px;
  }

  /* 六边形装饰 */
  .hex {
    width: 60px; height: 52px;
    background: rgba(0,212,255,0.1);
    border: 1px solid rgba(0,212,255,0.3);
    clip-path: polygon(25% 0%, 75% 0%, 100% 50%, 75% 100%, 25% 100%, 0% 50%);
    display: flex; align-items: center; justify-content: center;
    font-size: 22px;
  }

  /* 连接线装饰 */
  .connector {
    position: absolute;
    height: 1px;
    background: linear-gradient(90deg, var(--cyan), rgba(0,212,255,0.1));
    opacity: 0.4;
  }
</style>
</head>
<body>

<!-- 控制栏 -->
<div class="control-bar">
  <div class="bar-left">
    <div class="bar-logo">V</div>
    <div class="bar-brand">VMP加固技术</div>
    <div class="bar-page" id="pageIndicator">1 / 10</div>
  </div>
  <div class="bar-right">
    <button class="btn" id="btnPrev">◀ 上一页</button>
    <button class="btn" id="btnNext">下一页 ▶</button>
    <button class="btn btn-export" id="btnExport">📥 导出 PPTX</button>
  </div>
</div>

<!-- 进度条 -->
<div class="progress-wrap">
  <div class="progress-bar" id="progressBar" style="width:10%"></div>
</div>

<!-- 舞台 -->
<div class="stage-wrap">
  <div class="stage" id="stage">

    <!-- ══════════════════════════════════
         P1 · 封面页
    ══════════════════════════════════ -->
    <div class="slide active" id="slide-1">
      <div class="s-grid"></div>
      <!-- 背景光晕 -->
      <div style="position:absolute;inset:0;background:radial-gradient(ellipse at 30% 50%, rgba(10,42,90,0.8) 0%, #061529 70%);"></div>
      <!-- 装饰大圆 -->
      <div class="s-circle" style="width:420px;height:420px;right:-100px;bottom:-80px;"></div>
      <div class="s-circle" style="width:200px;height:200px;left:-40px;top:-40px;opacity:0.5;"></div>
      <!-- 右侧科技图形 -->
      <div style="position:absolute;right:5%;top:50%;transform:translateY(-50%);">
        <!-- 外圆 -->
        <div style="width:220px;height:220px;border-radius:50%;border:1px solid rgba(0,212,255,0.25);position:relative;display:flex;align-items:center;justify-content:center;">
          <!-- 中圆 -->
          <div style="width:160px;height:160px;border-radius:50%;border:1px solid rgba(0,212,255,0.4);position:relative;display:flex;align-items:center;justify-content:center;background:rgba(0,212,255,0.03);">
            <!-- 内圆 -->
            <div style="width:100px;height:100px;border-radius:50%;background:linear-gradient(135deg,rgba(0,212,255,0.15),rgba(0,102,204,0.2));border:1px solid rgba(0,212,255,0.6);display:flex;align-items:center;justify-content:center;box-shadow:0 0 30px rgba(0,212,255,0.3);">
              <span style="font-size:36px;">🛡️</span>
            </div>
            <!-- 轨道点 -->
            <div style="position:absolute;top:-5px;left:50%;width:10px;height:10px;background:var(--cyan);border-radius:50%;box-shadow:0 0 10px rgba(0,212,255,0.9);transform:translateX(-50%);"></div>
            <div style="position:absolute;bottom:-5px;right:10px;width:7px;height:7px;background:var(--orange);border-radius:50%;box-shadow:0 0 8px rgba(255,140,0,0.9);"></div>
          </div>
          <!-- 外轨道点 -->
          <div style="position:absolute;top:10px;right:5px;width:8px;height:8px;background:var(--green);border-radius:50%;box-shadow:0 0 8px rgba(0,255,136,0.9);"></div>
        </div>
      </div>
      <div class="s-topbar"></div>
      <div class="s-logo">VMP SEC</div>
      <!-- 内容 -->
      <div style="position:absolute;top:50%;left:5%;transform:translateY(-50%);max-width:58%;">
        <div class="badge" style="margin-bottom:18px;">ANDROID SECURITY · 2025</div>
        <div style="font-size:44px;font-weight:900;line-height:1.15;margin-bottom:16px;background:linear-gradient(135deg,#00d4ff 0%,#e8f4ff 50%,#00a8cc 100%);-webkit-background-clip:text;-webkit-text-fill-color:transparent;text-shadow:none;">
          安卓 VMP<br>虚拟机保护加固
        </div>
        <div style="font-size:15px;color:var(--gray);margin-bottom:24px;line-height:1.7;">
          Virtual Machine Protection · 深度技术解析<br>
          字节码虚拟化 · 指令混淆 · 反调试对抗
        </div>
        <div style="width:60px;height:3px;background:linear-gradient(90deg,var(--cyan),transparent);margin-bottom:20px;"></div>
        <div style="font-size:12px;color:var(--gray);letter-spacing:1px;">
          安全研究团队 &nbsp;|&nbsp; 移动安全实验室 &nbsp;|&nbsp; 2025.06
        </div>
      </div>
      <!-- 底部装饰条 -->
      <div style="position:absolute;bottom:0;left:0;right:0;height:2px;background:linear-gradient(90deg,transparent,var(--cyan),transparent);opacity:0.3;"></div>
    </div>

    <!-- ══════════════════════════════════
         P2 · 目录页
    ══════════════════════════════════ -->
    <div class="slide" id="slide-2">
      <div class="s-grid"></div>
      <div style="position:absolute;inset:0;background:radial-gradient(ellipse at 70% 30%, rgba(10,42,90,0.5) 0%, #061529 70%);"></div>
      <div class="s-circle" style="width:300px;height:300px;right:-50px;bottom:-60px;"></div>
      <div class="s-topbar"></div>
      <div class="s-logo">VMP SEC</div>
      <!-- 左侧青蓝栏 -->
      <div style="position:absolute;left:0;top:0;bottom:0;width:220px;background:linear-gradient(180deg,rgba(0,212,255,0.08) 0%,rgba(0,212,255,0.03) 100%);border-right:1px solid rgba(0,212,255,0.2);display:flex;flex-direction:column;justify-content:center;padding:30px 24px;">
        <div style="font-size:9px;letter-spacing:3px;color:var(--cyan);text-transform:uppercase;margin-bottom:12px;">CONTENTS</div>
        <div style="font-size:32px;font-weight:900;color:var(--white);line-height:1.2;margin-bottom:16px;">目录<br><span style="color:var(--cyan);text-shadow:0 0 15px rgba(0,212,255,0.7);">索引</span></div>
        <div style="width:40px;height:3px;background:var(--cyan);margin-bottom:12px;"></div>
        <div style="font-size:10px;color:var(--gray);line-height:1.7;">共 10 个核心章节<br>覆盖VMP全技术栈</div>
      </div>
      <!-- 右侧目录列表 -->
      <div style="position:absolute;left:240px;top:50%;transform:translateY(-50%);right:20px;">
        <!-- 目录项 -->
        <div style="display:flex;flex-direction:column;gap:7px;">
          <!-- 1 -->
          <div style="display:flex;align-items:center;gap:12px;padding:9px 14px;background:rgba(0,212,255,0.06);border:1px solid rgba(0,212,255,0.15);border-radius:8px;">
            <div style="width:26px;height:26px;background:linear-gradient(135deg,var(--cyan),#0066cc);border-radius:6px;display:flex;align-items:center;justify-content:center;font-size:11px;font-weight:900;color:#fff;flex-shrink:0;">01</div>
            <div style="flex:1;">
              <div style="font-size:12px;font-weight:700;color:var(--white);">VMP技术概述</div>
              <div style="font-size:9.5px;color:var(--gray);">虚拟机保护的起源与发展</div>
            </div>
            <span style="color:var(--cyan);font-size:14px;">›</span>
          </div>
          <!-- 2 -->
          <div style="display:flex;align-items:center;gap:12px;padding:9px 14px;background:rgba(10,31,61,0.8);border:1px solid var(--border);border-radius:8px;">
            <div style="width:26px;height:26px;background:linear-gradient(135deg,var(--orange),#cc5500);border-radius:6px;display:flex;align-items:center;justify-content:center;font-size:11px;font-weight:900;color:#fff;flex-shrink:0;">02</div>
            <div style="flex:1;">
              <div style="font-size:12px;font-weight:700;color:var(--white);">核心技术架构</div>
              <div style="font-size:9.5px;color:var(--gray);">字节码转换与虚拟指令集设计</div>
            </div>
            <span style="color:var(--cyan);font-size:14px;">›</span>
          </div>
          <!-- 3 -->
          <div style="display:flex;align-items:center;gap:12px;padding:9px 14px;background:rgba(10,31,61,0.8);border:1px solid var(--border);border-radius:8px;">
            <div style="width:26px;height:26px;background:linear-gradient(135deg,var(--green),#00aa55);border-radius:6px;display:flex;align-items:center;justify-content:center;font-size:11px;font-weight:900;color:#fff;flex-shrink:0;">03</div>
            <div style="flex:1;">
              <div style="font-size:12px;font-weight:700;color:var(--white);">保护能力矩阵</div>
              <div style="font-size:9.5px;color:var(--gray);">多层防护机制与反调试对抗</div>
            </div>
            <span style="color:var(--cyan);font-size:14px;">›</span>
          </div>
          <!-- 4 -->
          <div style="display:flex;align-items:center;gap:12px;padding:9px 14px;background:rgba(10,31,61,0.8);border:1px solid var(--border);border-radius:8px;">
            <div style="width:26px;height:26px;background:linear-gradient(135deg,var(--yellow),#cc9900);border-radius:6px;display:flex;align-items:center;justify-content:center;font-size:11px;font-weight:900;color:#fff;flex-shrink:0;">04</div>
            <div style="flex:1;">
              <div style="font-size:12px;font-weight:700;color:var(--white);">性能影响分析</div>
              <div style="font-size:9.5px;color:var(--gray);">加固前后性能对比与优化方案</div>
            </div>
            <span style="color:var(--cyan);font-size:14px;">›</span>
          </div>
          <!-- 5 -->
          <div style="display:flex;align-items:center;gap:12px;padding:9px 14px;background:rgba(10,31,61,0.8);border:1px solid var(--border);border-radius:8px;">
            <div style="width:26px;height:26px;background:linear-gradient(135deg,#aa44ff,#6600cc);border-radius:6px;display:flex;align-items:center;justify-content:center;font-size:11px;font-weight:900;color:#fff;flex-shrink:0;">05</div>
            <div style="flex:1;">
              <div style="font-size:12px;font-weight:700;color:var(--white);">攻防对抗实践</div>
              <div style="font-size:9.5px;color:var(--gray);">脱壳技术与防御升级策略</div>
            </div>
            <span style="color:var(--cyan);font-size:14px;">›</span>
          </div>
          <!-- 6 -->
          <div style="display:flex;align-items:center;gap:12px;padding:9px 14px;background:rgba(10,31,61,0.8);border:1px solid var(--border);border-radius:8px;">
            <div style="width:26px;height:26px;background:linear-gradient(135deg,#ff4488,#cc0044);border-radius:6px;display:flex;align-items:center;justify-content:center;font-size:11px;font-weight:900;color:#fff;flex-shrink:0;">06</div>
            <div style="flex:1;">
              <div style="font-size:12px;font-weight:700;color:var(--white);">行业应用与展望</div>
              <div style="font-size:9.5px;color:var(--gray);">主流方案对比与未来技术趋势</div>
            </div>
            <span style="color:var(--cyan);font-size:14px;">›</span>
          </div>
        </div>
      </div>
    </div>

    <!-- ══════════════════════════════════
         P3 · VMP概述 - 什么是VMP加固
    ══════════════════════════════════ -->
    <div class="slide" id="slide-3">
      <div class="s-grid"></div>
      <div style="position:absolute;inset:0;background:radial-gradient(ellipse at 20% 80%, rgba(10,42,90,0.6) 0%, #061529 70%);"></div>
      <div class="s-circle" style="width:350px;height:350px;right:-80px;top:-80px;"></div>
      <div class="s-topbar"></div>
      <div class="s-logo">VMP SEC</div>
      <div class="s-label">01 · VMP OVERVIEW</div>
      <div class="s-title" style="top:28px;">
        VMP 技术<span class="hl">概述</span> · 什么是虚拟机保护
      </div>
      <div class="s-divider" style="top:60px;left:20px;width:200px;"></div>

      <!-- 左侧核心说明 -->
      <div style="position:absolute;top:72px;left:20px;width:45%;bottom:12px;">
        <div style="background:rgba(10,31,61,0.9);border:1px solid rgba(0,212,255,0.2);border-radius:10px;padding:16px;height:100%;display:flex;flex-direction:column;gap:12px;">
          <div style="display:flex;align-items:center;gap:10px;margin-bottom:4px;">
            <div class="icon-box" style="background:rgba(0,212,255,0.15);">🔐</div>
            <div>
              <div style="font-size:13px;font-weight:700;color:var(--white);">VMP 核心定义</div>
              <div style="font-size:9.5px;color:var(--cyan);">VIRTUAL MACHINE PROTECTION</div>
            </div>
          </div>
          <div style="font-size:10.5px;color:var(--gray);line-height:1.7;padding-bottom:10px;border-bottom:1px solid rgba(0,212,255,0.1);">
            VMP(虚拟机保护)是将原始代码转换为<span style="color:var(--cyan);">自定义虚拟指令集</span>,
            由内置解释器执行,使攻击者无法直接逆向分析真实逻辑的保护技术。
          </div>

          <!-- 三大核心 -->
          <div style="display:flex;flex-direction:column;gap:8px;">
            <div style="display:flex;align-items:flex-start;gap:8px;">
              <div style="width:20px;height:20px;background:rgba(0,212,255,0.2);border:1px solid var(--cyan);border-radius:4px;display:flex;align-items:center;justify-content:center;font-size:10px;flex-shrink:0;margin-top:1px;">①</div>
              <div>
                <div style="font-size:11.5px;font-weight:700;color:var(--white);">字节码虚拟化</div>
                <div style="font-size:10px;color:var(--gray);">Dalvik/ART字节码 → 专有VM指令集,解释器动态执行</div>
              </div>
            </div>
            <div style="display:flex;align-items:flex-start;gap:8px;">
              <div style="width:20px;height:20px;background:rgba(255,140,0,0.2);border:1px solid var(--orange);border-radius:4px;display:flex;align-items:center;justify-content:center;font-size:10px;flex-shrink:0;margin-top:1px;color:var(--orange);">②</div>
              <div>
                <div style="font-size:11.5px;font-weight:700;color:var(--white);">指令混淆加密</div>
                <div style="font-size:10px;color:var(--gray);">多态指令、垃圾插入、控制流平坦化</div>
              </div>
            </div>
            <div style="display:flex;align-items:flex-start;gap:8px;">
              <div style="width:20px;height:20px;background:rgba(0,255,136,0.15);border:1px solid var(--green);border-radius:4px;display:flex;align-items:center;justify-content:center;font-size:10px;flex-shrink:0;margin-top:1px;color:var(--green);">③</div>
              <div>
                <div style="font-size:11.5px;font-weight:700;color:var(--white);">运行时保护</div>
                <div style="font-size:10px;color:var(--gray);">反调试、完整性校验、环境检测</div>
              </div>
            </div>
          </div>
        </div>
      </div>

      <!-- 右侧:技术演进时间轴 -->
      <div style="position:absolute;top:72px;left:48%;right:8px;bottom:12px;">
        <div style="font-size:11px;font-weight:700;color:var(--cyan);margin-bottom:12px;letter-spacing:1px;">📅 VMP技术演进时间轴</div>
        <!-- 时间轴 -->
        <div style="position:relative;padding-left:30px;">
          <div style="position:absolute;left:10px;top:5px;bottom:0;width:2px;background:linear-gradient(180deg,var(--cyan),rgba(0,212,255,0.1));"></div>

          <div style="position:relative;margin-bottom:14px;">
            <div style="position:absolute;left:-24px;top:3px;width:10px;height:10px;background:var(--cyan);border-radius:50%;box-shadow:0 0 8px rgba(0,212,255,0.8);"></div>
            <div style="font-size:10px;color:var(--cyan);font-weight:700;margin-bottom:2px;">2008 · 萌芽期</div>
            <div style="background:rgba(10,31,61,0.8);border:1px solid var(--border);border-radius:6px;padding:8px 10px;">
              <div style="font-size:10.5px;color:var(--white);font-weight:600;">桌面软件VMP技术兴起</div>
              <div style="font-size:9.5px;color:var(--gray);">VMProtect、Themida等工具出现,PC端代码保护兴起</div>
            </div>
          </div>

          <div style="position:relative;margin-bottom:14px;">
            <div style="position:absolute;left:-24px;top:3px;width:10px;height:10px;background:var(--orange);border-radius:50%;box-shadow:0 0 8px rgba(255,140,0,0.8);"></div>
            <div style="font-size:10px;color:var(--orange);font-weight:700;margin-bottom:2px;">2013 · 探索期</div>
            <div style="background:rgba(10,31,61,0.8);border:1px solid var(--border);border-radius:6px;padding:8px 10px;">
              <div style="font-size:10.5px;color:var(--white);font-weight:600;">移动安全需求爆发</div>
              <div style="font-size:9.5px;color:var(--gray);">Android生态快速扩张,逆向分析威胁显现,初代加固出现</div>
            </div>
          </div>

          <div style="position:relative;margin-bottom:14px;">
            <div style="position:absolute;left:-24px;top:3px;width:10px;height:10px;background:var(--green);border-radius:50%;box-shadow:0 0 8px rgba(0,255,136,0.8);"></div>
            <div style="font-size:10px;color:var(--green);font-weight:700;margin-bottom:2px;">2016 · 成熟期</div>
            <div style="background:rgba(10,31,61,0.8);border:1px solid var(--border);border-radius:6px;padding:8px 10px;">
              <div style="font-size:10.5px;color:var(--white);font-weight:600;">Android VMP技术成熟</div>
              <div style="font-size:9.5px;color:var(--gray);">腾讯、360等厂商推出商业VMP方案,金融/游戏行业广泛应用</div>
            </div>
          </div>

          <div style="position:relative;">
            <div style="position:absolute;left:-24px;top:3px;width:10px;height:10px;background:var(--yellow);border-radius:50%;box-shadow:0 0 8px rgba(255,215,0,0.8);"></div>
            <div style="font-size:10px;color:var(--yellow);font-weight:700;margin-bottom:2px;">2023 · 对抗期</div>
            <div style="background:rgba(10,31,61,0.8);border:1px solid var(--border);border-radius:6px;padding:8px 10px;">
              <div style="font-size:10.5px;color:var(--white);font-weight:600;">AI辅助攻防新格局</div>
              <div style="font-size:9.5px;color:var(--gray);">基于Frida/OLLVM的自动脱壳 vs AI驱动的智能混淆</div>
            </div>
          </div>
        </div>
      </div>
    </div>

    <!-- ══════════════════════════════════
         P4 · 核心技术架构
    ══════════════════════════════════ -->
    <div class="slide" id="slide-4">
      <div class="s-grid"></div>
      <div style="position:absolute;inset:0;background:radial-gradient(ellipse at 80% 20%, rgba(10,42,90,0.5) 0%, #061529 70%);"></div>
      <div class="s-circle" style="width:280px;height:280px;left:-60px;bottom:-40px;"></div>
      <div class="s-topbar"></div>
      <div class="s-logo">VMP SEC</div>
      <div class="s-label">02 · CORE ARCHITECTURE</div>
      <div class="s-title" style="top:28px;">
        核心技术<span class="hl">架构</span> · 字节码转换与指令集设计
      </div>
      <div class="s-divider" style="top:60px;left:20px;width:220px;"></div>

      <!-- 流程图:Dalvik → VMP引擎 → 解释器 -->
      <div style="position:absolute;top:72px;left:20px;right:20px;height:90px;">
        <div style="display:flex;align-items:center;gap:0;height:100%;">
          <!-- Step 1 -->
          <div class="flow-step" style="position:relative;width:16%;height:80px;left:auto;top:auto;">
            <div class="flow-num">1</div>
            <div style="font-size:10.5px;font-weight:700;color:var(--white);text-align:center;">原始 DEX</div>
            <div style="font-size:8.5px;color:var(--gray);text-align:center;">Dalvik字节码</div>
          </div>
          <!-- 箭头 -->
          <div style="flex:1;height:2px;background:linear-gradient(90deg,var(--cyan),var(--cyan));position:relative;">
            <div style="position:absolute;right:-8px;top:-5px;width:0;height:0;border-top:6px solid transparent;border-bottom:6px solid transparent;border-left:10px solid var(--cyan);"></div>
          </div>
          <!-- Step 2 -->
          <div class="flow-step" style="position:relative;width:16%;height:80px;left:auto;top:auto;background:rgba(0,212,255,0.08);border-color:rgba(0,212,255,0.4);">
            <div class="flow-num">2</div>
            <div style="font-size:10.5px;font-weight:700;color:var(--cyan);text-align:center;">指令分析</div>
            <div style="font-size:8.5px;color:var(--gray);text-align:center;">控制流图构建</div>
          </div>
          <!-- 箭头 -->
          <div style="flex:1;height:2px;background:var(--cyan);position:relative;">
            <div style="position:absolute;right:-8px;top:-5px;width:0;height:0;border-top:6px solid transparent;border-bottom:6px solid transparent;border-left:10px solid var(--cyan);"></div>
          </div>
          <!-- Step 3 -->
          <div class="flow-step" style="position:relative;width:16%;height:80px;left:auto;top:auto;background:rgba(255,140,0,0.08);border-color:rgba(255,140,0,0.4);">
            <div class="flow-num" style="background:linear-gradient(135deg,var(--orange),#cc5500);">3</div>
            <div style="font-size:10.5px;font-weight:700;color:var(--orange);text-align:center;">指令映射</div>
            <div style="font-size:8.5px;color:var(--gray);text-align:center;">自定义VM操作码</div>
          </div>
          <!-- 箭头 -->
          <div style="flex:1;height:2px;background:var(--orange);position:relative;">
            <div style="position:absolute;right:-8px;top:-5px;width:0;height:0;border-top:6px solid transparent;border-bottom:6px solid transparent;border-left:10px solid var(--orange);"></div>
          </div>
          <!-- Step 4 -->
          <div class="flow-step" style="position:relative;width:16%;height:80px;left:auto;top:auto;background:rgba(0,255,136,0.06);border-color:rgba(0,255,136,0.3);">
            <div class="flow-num" style="background:linear-gradient(135deg,var(--green),#00aa55);">4</div>
            <div style="font-size:10.5px;font-weight:700;color:var(--green);text-align:center;">加密打包</div>
            <div style="font-size:8.5px;color:var(--gray);text-align:center;">VM字节码+解释器</div>
          </div>
          <!-- 箭头 -->
          <div style="flex:1;height:2px;background:var(--green);position:relative;">
            <div style="position:absolute;right:-8px;top:-5px;width:0;height:0;border-top:6px solid transparent;border-bottom:6px solid transparent;border-left:10px solid var(--green);"></div>
          </div>
          <!-- Step 5 -->
          <div class="flow-step" style="position:relative;width:16%;height:80px;left:auto;top:auto;background:rgba(255,215,0,0.08);border-color:rgba(255,215,0,0.4);">
            <div class="flow-num" style="background:linear-gradient(135deg,var(--yellow),#cc9900);">5</div>
            <div style="font-size:10.5px;font-weight:700;color:var(--yellow);text-align:center;">运行时执行</div>
            <div style="font-size:8.5px;color:var(--gray);text-align:center;">解释器取指-译码</div>
          </div>
        </div>
      </div>

      <!-- 下方:3列技术卡片 -->
      <div style="position:absolute;top:175px;left:20px;right:20px;bottom:12px;display:grid;grid-template-columns:repeat(3,1fr);gap:10px;">
        <!-- 卡片1:虚拟寄存器 -->
        <div style="background:var(--bg2);border:1px solid var(--border);border-radius:10px;padding:14px;position:relative;overflow:hidden;">
          <div style="position:absolute;left:0;top:0;bottom:0;width:3px;background:var(--cyan);"></div>
          <div style="margin-left:8px;">
            <div style="font-size:18px;margin-bottom:8px;">⚙️</div>
            <div style="font-size:12px;font-weight:700;color:var(--white);margin-bottom:4px;">虚拟寄存器组</div>
            <div style="font-size:9px;color:var(--cyan);letter-spacing:1px;margin-bottom:8px;">VIRTUAL REGISTERS</div>
            <div style="font-size:9.5px;color:var(--gray);line-height:1.6;">
              模拟真实CPU寄存器,VPC(虚拟PC指针)控制执行流,
              VSP(虚拟栈指针)管理操作数栈,支持32/64位操作。
            </div>
            <!-- 代码示例 -->
            <div style="margin-top:8px;background:rgba(0,0,0,0.3);border-radius:4px;padding:6px;font-size:8.5px;color:#00ff88;font-family:monospace;line-height:1.5;">
              VPC → 取指 → 解码<br>
              VSP[n] ← 操作数<br>
              VReg[0..15] 通用寄存器
            </div>
          </div>
        </div>

        <!-- 卡片2:指令集设计 -->
        <div style="background:var(--bg2);border:1px solid var(--border);border-radius:10px;padding:14px;position:relative;overflow:hidden;">
          <div style="position:absolute;left:0;top:0;bottom:0;width:3px;background:var(--orange);"></div>
          <div style="margin-left:8px;">
            <div style="font-size:18px;margin-bottom:8px;">📋</div>
            <div style="font-size:12px;font-weight:700;color:var(--white);margin-bottom:4px;">自定义指令集</div>
            <div style="font-size:9px;color:var(--orange);letter-spacing:1px;margin-bottom:8px;">CUSTOM ISA</div>
            <div style="font-size:9.5px;color:var(--gray);line-height:1.6;">
              每次编译随机化操作码映射,同一逻辑不同版本产生完全不同字节序列,
              有效对抗基于特征的分析工具。
            </div>
            <div style="margin-top:8px;display:flex;flex-wrap:wrap;gap:4px;">
              <span class="card-tag">随机操作码</span>
              <span class="card-tag orange">多态混淆</span>
              <span class="card-tag">加密存储</span>
            </div>
          </div>
        </div>

        <!-- 卡片3:解释器引擎 -->
        <div style="background:var(--bg2);border:1px solid var(--border);border-radius:10px;padding:14px;position:relative;overflow:hidden;">
          <div style="position:absolute;left:0;top:0;bottom:0;width:3px;background:var(--green);"></div>
          <div style="margin-left:8px;">
            <div style="font-size:18px;margin-bottom:8px;">🔄</div>
            <div style="font-size:12px;font-weight:700;color:var(--white);margin-bottom:4px;">解释器引擎</div>
            <div style="font-size:9px;color:var(--green);letter-spacing:1px;margin-bottom:8px;">VM INTERPRETER</div>
            <div style="font-size:9.5px;color:var(--gray);line-height:1.6;">
              Native层高性能解释器,取指→解码→执行循环,
              通过JNI调用Android系统API,支持异常处理与反射。
            </div>
            <div style="margin-top:8px;background:rgba(0,0,0,0.3);border-radius:4px;padding:6px;font-size:8.5px;color:#00d4ff;font-family:monospace;line-height:1.5;">
              while(running) {<br>
              &nbsp;op = fetch(VPC++);<br>
              &nbsp;dispatch(op);<br>
              }
            </div>
          </div>
        </div>
      </div>
    </div>

    <!-- ══════════════════════════════════
         P5 · 保护能力矩阵
    ══════════════════════════════════ -->
    <div class="slide" id="slide-5">
      <div class="s-grid"></div>
      <div style="position:absolute;inset:0;background:radial-gradient(ellipse at 50% 80%, rgba(10,42,90,0.5) 0%, #061529 70%);"></div>
      <div class="s-circle" style="width:300px;height:300px;right:-60px;top:-60px;"></div>
      <div class="s-topbar"></div>
      <div class="s-logo">VMP SEC</div>
      <div class="s-label">03 · PROTECTION MATRIX</div>
      <div class="s-title" style="top:28px;">
        保护能力<span class="hl">矩阵</span> · 多层防护机制全景
      </div>
      <div class="s-divider" style="top:60px;left:20px;width:220px;"></div>

      <!-- 3×2 卡片网格 -->
      <div style="position:absolute;top:72px;left:20px;right:20px;bottom:12px;display:grid;grid-template-columns:repeat(3,1fr);grid-template-rows:repeat(2,1fr);gap:10px;">

        <!-- 卡片1:代码混淆 -->
        <div style="background:var(--bg2);border:1px solid var(--border);border-radius:10px;padding:14px;position:relative;overflow:hidden;box-shadow:0 0 20px rgba(0,212,255,0.08);">
          <div style="position:absolute;left:0;top:0;bottom:0;width:3px;background:var(--cyan);"></div>
          <div style="position:absolute;right:12px;top:12px;font-size:22px;opacity:0.6;">🌀</div>
          <div style="margin-left:8px;">
            <div class="card-sub">CODE OBFUSCATION</div>
            <div class="card-title">代码混淆</div>
            <div class="card-desc">控制流平坦化将清晰的顺序逻辑转化为状态机结构;字符串加密在运行时动态解密;垃圾代码插入增加分析难度。</div>
            <div style="margin-top:8px;">
              <span class="card-tag">控制流平坦化</span>
              <span class="card-tag" style="margin-left:4px;">字符串加密</span>
            </div>
          </div>
        </div>

        <!-- 卡片2:反调试 -->
        <div style="background:var(--bg2);border:1px solid var(--border);border-radius:10px;padding:14px;position:relative;overflow:hidden;box-shadow:0 0 20px rgba(255,140,0,0.08);">
          <div style="position:absolute;left:0;top:0;bottom:0;width:3px;background:var(--orange);"></div>
          <div style="position:absolute;right:12px;top:12px;font-size:22px;opacity:0.6;">🚫</div>
          <div style="margin-left:8px;">
            <div class="card-sub" style="color:var(--orange);">ANTI-DEBUG</div>
            <div class="card-title">反调试对抗</div>
            <div class="card-desc">检测TracerPID、ptrace占坑;监测调试端口4444/5555;时序检测:rdtsc/clock_gettime时间差分析;/proc/maps扫描。</div>
            <div style="margin-top:8px;">
              <span class="card-tag orange">TracerPID检测</span>
              <span class="card-tag orange" style="margin-left:4px;">时序校验</span>
            </div>
          </div>
        </div>

        <!-- 卡片3:完整性校验 -->
        <div style="background:var(--bg2);border:1px solid var(--border);border-radius:10px;padding:14px;position:relative;overflow:hidden;box-shadow:0 0 20px rgba(0,255,136,0.06);">
          <div style="position:absolute;left:0;top:0;bottom:0;width:3px;background:var(--green);"></div>
          <div style="position:absolute;right:12px;top:12px;font-size:22px;opacity:0.6;">✅</div>
          <div style="margin-left:8px;">
            <div class="card-sub" style="color:var(--green);">INTEGRITY CHECK</div>
            <div class="card-title">完整性校验</div>
            <div class="card-desc">对DEX/APK/SO文件进行CRC32/SHA256校验;签名验证防止二次打包;内存代码段哈希比对防止运行时篡改。</div>
            <div style="margin-top:8px;">
              <span class="card-tag green">CRC32校验</span>
              <span class="card-tag green" style="margin-left:4px;">签名验证</span>
            </div>
          </div>
        </div>

        <!-- 卡片4:环境检测 -->
        <div style="background:var(--bg2);border:1px solid var(--border);border-radius:10px;padding:14px;position:relative;overflow:hidden;box-shadow:0 0 20px rgba(255,215,0,0.06);">
          <div style="position:absolute;left:0;top:0;bottom:0;width:3px;background:var(--yellow);"></div>
          <div style="position:absolute;right:12px;top:12px;font-size:22px;opacity:0.6;">🔍</div>
          <div style="margin-left:8px;">
            <div class="card-sub" style="color:var(--yellow);">ENV DETECTION</div>
            <div class="card-title">环境检测</div>
            <div class="card-desc">检测Root/Xposed/Magisk框架;识别模拟器特征(QEMU/Genymotion);Hook框架检测:Frida agent、Substrate特征扫描。</div>
            <div style="margin-top:8px;">
              <span class="card-tag" style="color:var(--yellow);border-color:rgba(255,215,0,0.3);background:rgba(255,215,0,0.08);">Root检测</span>
              <span class="card-tag" style="margin-left:4px;color:var(--yellow);border-color:rgba(255,215,0,0.3);background:rgba(255,215,0,0.08);">Frida检测</span>
            </div>
          </div>
        </div>

        <!-- 卡片5:SO加固 -->
        <div style="background:var(--bg2);border:1px solid var(--border);border-radius:10px;padding:14px;position:relative;overflow:hidden;box-shadow:0 0 20px rgba(170,68,255,0.08);">
          <div style="position:absolute;left:0;top:0;bottom:0;width:3px;background:#aa44ff;"></div>
          <div style="position:absolute;right:12px;top:12px;font-size:22px;opacity:0.6;">📦</div>
          <div style="margin-left:8px;">
            <div class="card-sub" style="color:#aa44ff;">SO PROTECTION</div>
            <div class="card-title">SO 文件加固</div>
            <div class="card-desc">ELF Section加密;符号表清除;OLLVM编译混淆;自定义linker动态加载;函数粒度加解密,防IDA静态分析。</div>
            <div style="margin-top:8px;">
              <span class="card-tag" style="color:#aa44ff;border-color:rgba(170,68,255,0.3);background:rgba(170,68,255,0.08);">ELF加密</span>
              <span class="card-tag" style="margin-left:4px;color:#aa44ff;border-color:rgba(170,68,255,0.3);background:rgba(170,68,255,0.08);">OLLVM</span>
            </div>
          </div>
        </div>

        <!-- 卡片6:资源保护 -->
        <div style="background:var(--bg2);border:1px solid var(--border);border-radius:10px;padding:14px;position:relative;overflow:hidden;box-shadow:0 0 20px rgba(255,68,136,0.06);">
          <div style="position:absolute;left:0;top:0;bottom:0;width:3px;background:#ff4488;"></div>
          <div style="position:absolute;right:12px;top:12px;font-size:22px;opacity:0.6;">🎨</div>
          <div style="margin-left:8px;">
            <div class="card-sub" style="color:#ff4488;">RESOURCE GUARD</div>
            <div class="card-title">资源文件保护</div>
            <div class="card-desc">Assets/Res目录加密打包;资源索引混淆;布局文件混淆防UI逆向;Manifest关键信息隐藏。</div>
            <div style="margin-top:8px;">
              <span class="card-tag red">资源加密</span>
              <span class="card-tag red" style="margin-left:4px;">布局混淆</span>
            </div>
          </div>
        </div>

      </div>
    </div>

    <!-- ══════════════════════════════════
         P6 · 性能影响分析
    ══════════════════════════════════ -->
    <div class="slide" id="slide-6">
      <div class="s-grid"></div>
      <div style="position:absolute;inset:0;background:radial-gradient(ellipse at 20% 50%, rgba(10,42,90,0.6) 0%, #061529 70%);"></div>
      <div class="s-circle" style="width:320px;height:320px;right:-80px;bottom:-60px;"></div>
      <div class="s-topbar"></div>
      <div class="s-logo">VMP SEC</div>
      <div class="s-label">04 · PERFORMANCE ANALYSIS</div>
      <div class="s-title" style="top:28px;">
        性能影响<span class="hl">分析</span> · 加固代价与优化权衡
      </div>
      <div class="s-divider" style="top:60px;left:20px;width:220px;"></div>

      <!-- 左侧进度条区 -->
      <div style="position:absolute;top:72px;left:20px;width:54%;bottom:12px;">
        <div style="background:var(--bg2);border:1px solid var(--border);border-radius:10px;padding:18px;height:100%;">
          <div style="font-size:12px;font-weight:700;color:var(--white);margin-bottom:14px;">📊 关键性能指标对比(加固前→加固后)</div>

          <!-- 启动时间 -->
          <div style="margin-bottom:16px;">
            <div style="display:flex;justify-content:space-between;align-items:center;margin-bottom:6px;">
              <div style="font-size:10.5px;color:var(--white);">冷启动时间</div>
              <div style="font-size:16px;font-weight:900;color:var(--yellow);text-shadow:0 0 15px rgba(255,215,0,0.7);">+35%</div>
            </div>
            <div style="display:flex;gap:6px;align-items:center;">
              <div style="font-size:9px;color:var(--gray);width:28px;">前</div>
              <div class="prog-track" style="flex:1;">
                <div class="prog-fill" style="width:45%;background:linear-gradient(90deg,var(--green),#00aa55);"></div>
              </div>
              <div style="font-size:9px;color:var(--green);width:36px;">820ms</div>
            </div>
            <div style="display:flex;gap:6px;align-items:center;margin-top:4px;">
              <div style="font-size:9px;color:var(--gray);width:28px;">后</div>
              <div class="prog-track" style="flex:1;">
                <div class="prog-fill" style="width:61%;background:linear-gradient(90deg,var(--orange),#cc5500);"></div>
              </div>
              <div style="font-size:9px;color:var(--orange);width:36px;">1108ms</div>
            </div>
          </div>

          <!-- 方法执行效率 -->
          <div style="margin-bottom:16px;">
            <div style="display:flex;justify-content:space-between;align-items:center;margin-bottom:6px;">
              <div style="font-size:10.5px;color:var(--white);">VM解释执行效率</div>
              <div style="font-size:16px;font-weight:900;color:var(--orange);text-shadow:0 0 15px rgba(255,140,0,0.7);">-60%</div>
            </div>
            <div style="display:flex;gap:6px;align-items:center;">
              <div style="font-size:9px;color:var(--gray);width:28px;">前</div>
              <div class="prog-track" style="flex:1;">
                <div class="prog-fill" style="width:90%;background:linear-gradient(90deg,var(--green),#00aa55);"></div>
              </div>
              <div style="font-size:9px;color:var(--green);width:36px;">100%</div>
            </div>
            <div style="display:flex;gap:6px;align-items:center;margin-top:4px;">
              <div style="font-size:9px;color:var(--gray);width:28px;">后</div>
              <div class="prog-track" style="flex:1;">
                <div class="prog-fill" style="width:36%;background:linear-gradient(90deg,#ff4444,#cc0000);"></div>
              </div>
              <div style="font-size:9px;color:#ff6666;width:36px;">40%</div>
            </div>
          </div>

          <!-- 包体积 -->
          <div style="margin-bottom:16px;">
            <div style="display:flex;justify-content:space-between;align-items:center;margin-bottom:6px;">
              <div style="font-size:10.5px;color:var(--white);">APK 包体积增量</div>
              <div style="font-size:16px;font-weight:900;color:var(--cyan);text-shadow:0 0 15px rgba(0,212,255,0.7);">+3~8MB</div>
            </div>
            <div style="display:flex;gap:6px;align-items:center;">
              <div style="font-size:9px;color:var(--gray);width:28px;">前</div>
              <div class="prog-track" style="flex:1;">
                <div class="prog-fill" style="width:40%;"></div>
              </div>
              <div style="font-size:9px;color:var(--cyan);width:36px;">~20MB</div>
            </div>
            <div style="display:flex;gap:6px;align-items:center;margin-top:4px;">
              <div style="font-size:9px;color:var(--gray);width:28px;">后</div>
              <div class="prog-track" style="flex:1;">
                <div class="prog-fill" style="width:56%;"></div>
              </div>
              <div style="font-size:9px;color:var(--cyan);width:36px;">~28MB</div>
            </div>
          </div>

          <!-- 内存占用 -->
          <div>
            <div style="display:flex;justify-content:space-between;align-items:center;margin-bottom:6px;">
              <div style="font-size:10.5px;color:var(--white);">运行时内存增量</div>
              <div style="font-size:16px;font-weight:900;color:var(--yellow);text-shadow:0 0 15px rgba(255,215,0,0.7);">+20%</div>
            </div>
            <div style="display:flex;gap:6px;align-items:center;">
              <div style="font-size:9px;color:var(--gray);width:28px;">前</div>
              <div class="prog-track" style="flex:1;">
                <div class="prog-fill" style="width:50%;background:linear-gradient(90deg,var(--green),#00aa55);"></div>
              </div>
              <div style="font-size:9px;color:var(--green);width:36px;">120MB</div>
            </div>
            <div style="display:flex;gap:6px;align-items:center;margin-top:4px;">
              <div style="font-size:9px;color:var(--gray);width:28px;">后</div>
              <div class="prog-track" style="flex:1;">
                <div class="prog-fill" style="width:60%;background:linear-gradient(90deg,var(--yellow),#cc9900);"></div>
              </div>
              <div style="font-size:9px;color:var(--yellow);width:36px;">144MB</div>
            </div>
          </div>
        </div>
      </div>

      <!-- 右侧:优化策略 + 关键数据 -->
      <div style="position:absolute;top:72px;left:57%;right:8px;bottom:12px;display:flex;flex-direction:column;gap:10px;">

        <!-- 数据卡片 -->
        <div style="display:grid;grid-template-columns:1fr 1fr;gap:10px;flex-shrink:0;">
          <div style="background:var(--bg2);border:1px solid var(--border);border-radius:10px;padding:12px;text-align:center;">
            <div class="big-num" style="font-size:32px;">5-15%</div>
            <div style="font-size:9.5px;color:var(--gray);margin-top:4px;">核心业务方法<br>建议VMP保护比例</div>
          </div>
          <div style="background:var(--bg2);border:1px solid var(--border);border-radius:10px;padding:12px;text-align:center;">
            <div class="big-num cyan" style="font-size:32px;">3~5x</div>
            <div style="font-size:9.5px;color:var(--gray);margin-top:4px;">VM解释执行<br>相对JIT的性能损耗</div>
          </div>
        </div>

        <!-- 优化策略卡片 -->
        <div style="background:var(--bg2);border:1px solid var(--border);border-radius:10px;padding:14px;flex:1;overflow:hidden;position:relative;">
          <div style="position:absolute;left:0;top:0;bottom:0;width:3px;background:var(--green);"></div>
          <div style="margin-left:8px;">
            <div style="font-size:11px;font-weight:700;color:var(--white);margin-bottom:10px;">⚡ 性能优化策略</div>
            <div style="display:flex;flex-direction:column;gap:7px;">
              <div style="display:flex;align-items:flex-start;gap:7px;">
                <div style="width:16px;height:16px;background:rgba(0,212,255,0.2);border-radius:3px;display:flex;align-items:center;justify-content:center;font-size:9px;flex-shrink:0;color:var(--cyan);">✓</div>
                <div>
                  <div style="font-size:10.5px;color:var(--white);font-weight:600;">精准保护选择</div>
                  <div style="font-size:9px;color:var(--gray);">仅对核心支付/密钥算法开启VMP,UI层不加固</div>
                </div>
              </div>
              <div style="display:flex;align-items:flex-start;gap:7px;">
                <div style="width:16px;height:16px;background:rgba(255,140,0,0.2);border-radius:3px;display:flex;align-items:center;justify-content:center;font-size:9px;flex-shrink:0;color:var(--orange);">✓</div>
                <div>
                  <div style="font-size:10.5px;color:var(--white);font-weight:600;">分级保护策略</div>
                  <div style="font-size:9px;color:var(--gray);">高危方法VMP+反调试,普通方法仅做代码混淆</div>
                </div>
              </div>
              <div style="display:flex;align-items:flex-start;gap:7px;">
                <div style="width:16px;height:16px;background:rgba(0,255,136,0.15);border-radius:3px;display:flex;align-items:center;justify-content:center;font-size:9px;flex-shrink:0;color:var(--green);">✓</div>
                <div>
                  <div style="font-size:10.5px;color:var(--white);font-weight:600;">懒加载解密</div>
                  <div style="font-size:9px;color:var(--gray);">VM字节码按需解密,减少启动时解密开销</div>
                </div>
              </div>
              <div style="display:flex;align-items:flex-start;gap:7px;">
                <div style="width:16px;height:16px;background:rgba(255,215,0,0.15);border-radius:3px;display:flex;align-items:center;justify-content:center;font-size:9px;flex-shrink:0;color:var(--yellow);">✓</div>
                <div>
                  <div style="font-size:10.5px;color:var(--white);font-weight:600;">解释器性能调优</div>
                  <div style="font-size:9px;color:var(--gray);">Threaded dispatch代替switch-case,减少分支预测开销</div>
                </div>
              </div>
            </div>
          </div>
        </div>
      </div>
    </div>

    <!-- ══════════════════════════════════
         P7 · 攻防对抗:脱壳技术
    ══════════════════════════════════ -->
    <div class="slide" id="slide-7">
      <div class="s-grid"></div>
      <div style="position:absolute;inset:0;background:radial-gradient(ellipse at 30% 30%, rgba(50,10,10,0.4) 0%, #061529 70%);"></div>
      <div class="s-circle" style="width:280px;height:280px;right:-50px;bottom:-40px;"></div>
      <div class="s-topbar" style="background:linear-gradient(90deg,#ff4444,var(--orange),transparent);"></div>
      <div class="s-logo">VMP SEC</div>
      <div class="s-label" style="color:var(--orange);">05 · ATTACK & DEFENSE</div>
      <div class="s-title" style="top:28px;">
        攻防<span style="color:var(--orange);text-shadow:0 0 15px rgba(255,140,0,0.7);">对抗实践</span> · 脱壳技术与防御升级
      </div>
      <div class="s-divider" style="top:60px;left:20px;width:220px;background:linear-gradient(90deg,var(--orange),transparent);"></div>

      <!-- 对抗矩阵:左攻右防 -->
      <div style="position:absolute;top:72px;left:20px;right:20px;bottom:12px;display:flex;gap:10px;align-items:stretch;">

        <!-- 攻击侧 -->
        <div style="flex:1;display:flex;flex-direction:column;gap:8px;">
          <div style="background:rgba(100,20,20,0.3);border:1px solid rgba(255,68,68,0.3);border-radius:8px;padding:8px 12px;text-align:center;">
            <div style="font-size:11px;font-weight:700;color:#ff6666;letter-spacing:2px;">⚔️ 攻击方(脱壳者)</div>
          </div>

          <div style="background:var(--bg2);border:1px solid rgba(255,68,68,0.2);border-radius:8px;padding:12px;position:relative;overflow:hidden;flex:1;">
            <div style="position:absolute;left:0;top:0;bottom:0;width:3px;background:#ff4444;"></div>
            <div style="margin-left:8px;">
              <div style="font-size:10.5px;font-weight:700;color:#ff6666;margin-bottom:8px;">🔓 Frida Hook脱壳</div>
              <div style="background:rgba(0,0,0,0.4);border-radius:4px;padding:8px;font-size:8.5px;color:#ff9999;font-family:monospace;line-height:1.6;margin-bottom:8px;">
                // Hook DexFile构造函数<br>
                Java.use('dalvik.system<br>
                .DexFile').$init.overload()<br>
                .implementation = function(){<br>
                &nbsp;&nbsp;dumpDex(this);<br>
                }
              </div>
              <div style="font-size:9.5px;color:var(--gray);line-height:1.5;">在DexClassLoader/InMemoryDexClassLoader时机转储内存中已解密的DEX字节码</div>
            </div>
          </div>

          <div style="background:var(--bg2);border:1px solid rgba(255,68,68,0.2);border-radius:8px;padding:12px;position:relative;overflow:hidden;flex:1;">
            <div style="position:absolute;left:0;top:0;bottom:0;width:3px;background:#ff6644;"></div>
            <div style="margin-left:8px;">
              <div style="font-size:10.5px;font-weight:700;color:#ff8866;margin-bottom:8px;">🔓 FART/ART Hook</div>
              <div style="font-size:9.5px;color:var(--gray);line-height:1.55;">
                修改ART解释器源码,在ExecuteSwitchImpl执行入口处主动调用DexFile中每个方法,强制触发整体脱壳(FART方案)
              </div>
              <div style="margin-top:6px;">
                <span class="card-tag red">主动调用</span>
                <span class="card-tag red" style="margin-left:4px;">内存dump</span>
              </div>
            </div>
          </div>

          <div style="background:var(--bg2);border:1px solid rgba(255,68,68,0.2);border-radius:8px;padding:12px;position:relative;overflow:hidden;flex:1;">
            <div style="position:absolute;left:0;top:0;bottom:0;width:3px;background:#ff4488;"></div>
            <div style="margin-left:8px;">
              <div style="font-size:10.5px;font-weight:700;color:#ff88bb;margin-bottom:8px;">🔓 VMP指令语义分析</div>
              <div style="font-size:9.5px;color:var(--gray);line-height:1.55;">
                通过动态插桩记录VM解释器执行轨迹,结合符号执行还原VM指令语义,重建控制流图实现部分还原
              </div>
              <div style="margin-top:6px;">
                <span class="card-tag red">符号执行</span>
                <span class="card-tag red" style="margin-left:4px;">轨迹分析</span>
              </div>
            </div>
          </div>
        </div>

        <!-- 中间VS -->
        <div style="width:50px;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:8px;flex-shrink:0;">
          <div style="width:1px;flex:1;background:linear-gradient(180deg,transparent,rgba(0,212,255,0.3),transparent);"></div>
          <div style="width:40px;height:40px;border-radius:50%;background:linear-gradient(135deg,rgba(255,68,68,0.3),rgba(0,212,255,0.3));border:1px solid rgba(0,212,255,0.4);display:flex;align-items:center;justify-content:center;font-size:10px;font-weight:900;color:var(--white);">VS</div>
          <div style="width:1px;flex:1;background:linear-gradient(180deg,transparent,rgba(0,212,255,0.3),transparent);"></div>
        </div>

        <!-- 防御侧 -->
        <div style="flex:1;display:flex;flex-direction:column;gap:8px;">
          <div style="background:rgba(0,80,40,0.3);border:1px solid rgba(0,212,255,0.3);border-radius:8px;padding:8px 12px;text-align:center;">
            <div style="font-size:11px;font-weight:700;color:var(--cyan);letter-spacing:2px;">🛡️ 防御方(加固者)</div>
          </div>

          <div style="background:var(--bg2);border:1px solid rgba(0,212,255,0.2);border-radius:8px;padding:12px;position:relative;overflow:hidden;flex:1;">
            <div style="position:absolute;left:0;top:0;bottom:0;width:3px;background:var(--cyan);"></div>
            <div style="margin-left:8px;">
              <div style="font-size:10.5px;font-weight:700;color:var(--cyan);margin-bottom:8px;">🛡️ Frida检测对抗</div>
              <div style="font-size:9.5px;color:var(--gray);line-height:1.55;">
                扫描/proc/maps中frida-agent特征;检测frida-server监听端口27042;
                内存特征扫描检测inline hook痕迹;JNI函数完整性验证
              </div>
              <div style="margin-top:6px;">
                <span class="card-tag">端口检测</span>
                <span class="card-tag" style="margin-left:4px;">内存扫描</span>
              </div>
            </div>
          </div>

          <div style="background:var(--bg2);border:1px solid rgba(0,212,255,0.2);border-radius:8px;padding:12px;position:relative;overflow:hidden;flex:1;">
            <div style="position:absolute;left:0;top:0;bottom:0;width:3px;background:var(--green);"></div>
            <div style="margin-left:8px;">
              <div style="font-size:10.5px;font-weight:700;color:var(--green);margin-bottom:8px;">🛡️ 函数粒度加解密</div>
              <div style="font-size:9.5px;color:var(--gray);line-height:1.55;">
                方法调用前即时解密,执行完毕立即重新加密覆盖内存,
                使内存dump工具无法在空闲时获取完整可用DEX(Java-over-VMP)
              </div>
              <div style="margin-top:6px;">
                <span class="card-tag green">即时解密</span>
                <span class="card-tag green" style="margin-left:4px;">用后销毁</span>
              </div>
            </div>
          </div>

          <div style="background:var(--bg2);border:1px solid rgba(0,212,255,0.2);border-radius:8px;padding:12px;position:relative;overflow:hidden;flex:1;">
            <div style="position:absolute;left:0;top:0;bottom:0;width:3px;background:var(--yellow);"></div>
            <div style="margin-left:8px;">
              <div style="font-size:10.5px;font-weight:700;color:var(--yellow);margin-bottom:8px;">🛡️ 语义混淆加深</div>
              <div style="font-size:9.5px;color:var(--gray);line-height:1.55;">
                VM指令集随机化+多态混淆+虚假数据流插入,使符号执行路径爆炸;
                指令Handler本身也经OLLVM混淆,大幅提升分析成本
              </div>
              <div style="margin-top:6px;">
                <span class="card-tag" style="color:var(--yellow);border-color:rgba(255,215,0,0.3);background:rgba(255,215,0,0.08);">路径爆炸</span>
                <span class="card-tag" style="margin-left:4px;color:var(--yellow);border-color:rgba(255,215,0,0.3);background:rgba(255,215,0,0.08);">双重混淆</span>
              </div>
            </div>
          </div>
        </div>
      </div>
    </div>

    <!-- ══════════════════════════════════
         P8 · 主流方案对比
    ══════════════════════════════════ -->
    <div class="slide" id="slide-8">
      <div class="s-grid"></div>
      <div style="position:absolute;inset:0;background:radial-gradient(ellipse at 70% 70%, rgba(10,42,90,0.5) 0%, #061529 70%);"></div>
      <div class="s-circle" style="width:260px;height:260px;left:-50px;top:-40px;"></div>
      <div class="s-topbar"></div>
      <div class="s-logo">VMP SEC</div>
      <div class="s-label">06 · SOLUTION COMPARISON</div>
      <div class="s-title" style="top:28px;">
        主流方案<span class="hl">对比</span> · 商业加固选型参考
      </div>
      <div class="s-divider" style="top:60px;left:20px;width:220px;"></div>

      <!-- 对比表格 -->
      <div style="position:absolute;top:72px;left:20px;right:20px;bottom:12px;">
        <div style="background:var(--bg2);border:1px solid var(--border);border-radius:10px;overflow:hidden;height:100%;">

          <!-- 表头 -->
          <div style="display:grid;grid-template-columns:120px 1fr 1fr 1fr 1fr 1fr;background:rgba(0,212,255,0.1);border-bottom:1px solid rgba(0,212,255,0.2);padding:10px 12px;gap:8px;align-items:center;">
            <div style="font-size:10px;color:var(--gray);">对比维度</div>
            <div style="text-align:center;">
              <div style="font-size:10px;font-weight:700;color:var(--cyan);">腾讯乐固</div>
              <div style="font-size:8px;color:var(--gray);">Tencent</div>
            </div>
            <div style="text-align:center;">
              <div style="font-size:10px;font-weight:700;color:var(--orange);">阿里聚安全</div>
              <div style="font-size:8px;color:var(--gray);">Alibaba</div>
            </div>
            <div style="text-align:center;">
              <div style="font-size:10px;font-weight:700;color:var(--green);">360加固</div>
              <div style="font-size:8px;color:var(--gray);">Qihoo</div>
            </div>
            <div style="text-align:center;">
              <div style="font-size:10px;font-weight:700;color:var(--yellow);">梆梆安全</div>
              <div style="font-size:8px;color:var(--gray);">Bangcle</div>
            </div>
            <div style="text-align:center;">
              <div style="font-size:10px;font-weight:700;color:#aa44ff;">网易易盾</div>
              <div style="font-size:8px;color:var(--gray);">NetEase</div>
            </div>
          </div>

          <!-- 数据行 -->
          <div style="padding:0 12px;overflow:auto;height:calc(100% - 52px);">

            <!-- 行1 -->
            <div style="display:grid;grid-template-columns:120px 1fr 1fr 1fr 1fr 1fr;padding:10px 0;gap:8px;border-bottom:1px solid rgba(0,212,255,0.06);align-items:center;">
              <div style="font-size:10px;color:var(--gray);">VMP支持</div>
              <div style="text-align:center;font-size:14px;">✅</div>
              <div style="text-align:center;font-size:14px;">✅</div>
              <div style="text-align:center;font-size:14px;">✅</div>
              <div style="text-align:center;font-size:14px;">✅</div>
              <div style="text-align:center;font-size:14px;">✅</div>
            </div>

            <!-- 行2 -->
            <div style="display:grid;grid-template-columns:120px 1fr 1fr 1fr 1fr 1fr;padding:10px 0;gap:8px;border-bottom:1px solid rgba(0,212,255,0.06);align-items:center;">
              <div style="font-size:10px;color:var(--gray);">保护强度</div>
              <div style="text-align:center;">
                <div style="display:flex;justify-content:center;gap:2px;">
                  <div style="width:8px;height:8px;border-radius:2px;background:var(--cyan);"></div>
                  <div style="width:8px;height:8px;border-radius:2px;background:var(--cyan);"></div>
                  <div style="width:8px;height:8px;border-radius:2px;background:var(--cyan);"></div>
                  <div style="width:8px;height:8px;border-radius:2px;background:var(--cyan);"></div>
                  <div style="width:8px;height:8px;border-radius:2px;background:rgba(0,212,255,0.2);"></div>
                </div>
              </div>
              <div style="text-align:center;">
                <div style="display:flex;justify-content:center;gap:2px;">
                  <div style="width:8px;height:8px;border-radius:2px;background:var(--orange);"></div>
                  <div style="width:8px;height:8px;border-radius:2px;background:var(--orange);"></div>
                  <div style="width:8px;height:8px;border-radius:2px;background:var(--orange);"></div>
                  <div style="width:8px;height:8px;border-radius:2px;background:var(--orange);"></div>
                  <div style="width:8px;height:8px;border-radius:2px;background:rgba(255,140,0,0.2);"></div>
                </div>
              </div>
              <div style="text-align:center;">
                <div style="display:flex;justify-content:center;gap:2px;">
                  <div style="width:8px;height:8px;border-radius:2px;background:var(--green);"></div>
                  <div style="width:8px;height:8px;border-radius:2px;background:var(--green);"></div>
                  <div style="width:8px;height:8px;border-radius:2px;background:var(--green);"></div>
                  <div style="width:8px;height:8px;border-radius:2px;background:rgba(0,255,136,0.2);"></div>
                  <div style="width:8px;height:8px;border-radius:2px;background:rgba(0,255,136,0.2);"></div>
                </div>
              </div>
              <div style="text-align:center;">
                <div style="display:flex;justify-content:center;gap:2px;">
                  <div style="width:8px;height:8px;border-radius:2px;background:var(--yellow);"></div>
                  <div style="width:8px;height:8px;border-radius:2px;background:var(--yellow);"></div>
                  <div style="width:8px;height:8px;border-radius:2px;background:var(--yellow);"></div>
                  <div style="width:8px;height:8px;border-radius:2px;background:var(--yellow);"></div>
                  <div style="width:8px;height:8px;border-radius:2px;background:var(--yellow);"></div>
                </div>
              </div>
              <div style="text-align:center;">
                <div style="display:flex;justify-content:center;gap:2px;">
                  <div style="width:8px;height:8px;border-radius:2px;background:#aa44ff;"></div>
                  <div style="width:8px;height:8px;border-radius:2px;background:#aa44ff;"></div>
                  <div style="width:8px;height:8px;border-radius:2px;background:#aa44ff;"></div>
                  <div style="width:8px;height:8px;border-radius:2px;background:#aa44ff;"></div>
                  <div style="width:8px;height:8px;border-radius:2px;background:rgba(170,68,255,0.2);"></div>
                </div>
              </div>
            </div>

            <!-- 行3 -->
            <div style="display:grid;grid-template-columns:120px 1fr 1fr 1fr 1fr 1fr;padding:10px 0;gap:8px;border-bottom:1px solid rgba(0,212,255,0.06);align-items:center;">
              <div style="font-size:10px;color:var(--gray);">性能损耗</div>
              <div style="text-align:center;font-size:10px;color:var(--yellow);font-weight:700;">中 ~30%</div>
              <div style="text-align:center;font-size:10px;color:var(--green);font-weight:700;">低 ~25%</div>
              <div style="text-align:center;font-size:10px;color:var(--orange);font-weight:700;">中 ~35%</div>
              <div style="text-align:center;font-size:10px;color:var(--cyan);font-weight:700;">低 ~20%</div>
              <div style="text-align:center;font-size:10px;color:var(--orange);font-weight:700;">中 ~30%</div>
            </div>

            <!-- 行4 -->
            <div style="display:grid;grid-template-columns:120px 1fr 1fr 1fr 1fr 1fr;padding:10px 0;gap:8px;border-bottom:1px solid rgba(0,212,255,0.06);align-items:center;">
              <div style="font-size:10px;color:var(--gray);">SO加固</div>
              <div style="text-align:center;font-size:14px;">✅</div>
              <div style="text-align:center;font-size:14px;">✅</div>
              <div style="text-align:center;font-size:14px;">✅</div>
              <div style="text-align:center;font-size:14px;">⚠️</div>
              <div style="text-align:center;font-size:14px;">✅</div>
            </div>

            <!-- 行5 -->
            <div style="display:grid;grid-template-columns:120px 1fr 1fr 1fr 1fr 1fr;padding:10px 0;gap:8px;border-bottom:1px solid rgba(0,212,255,0.06);align-items:center;">
              <div style="font-size:10px;color:var(--gray);">适用场景</div>
              <div style="text-align:center;font-size:9px;color:var(--gray);">游戏/微信生态</div>
              <div style="text-align:center;font-size:9px;color:var(--gray);">金融/电商</div>
              <div style="text-align:center;font-size:9px;color:var(--gray);">互联网通用</div>
              <div style="text-align:center;font-size:9px;color:var(--gray);">企业级应用</div>
              <div style="text-align:center;font-size:9px;color:var(--gray);">游戏/工具</div>
            </div>

            <!-- 行6 -->
            <div style="display:grid;grid-template-columns:120px 1fr 1fr 1fr 1fr 1fr;padding:10px 0;gap:8px;align-items:center;">
              <div style="font-size:10px;color:var(--gray);">收费模式</div>
              <div style="text-align:center;font-size:9px;color:var(--cyan);">按次/订阅</div>
              <div style="text-align:center;font-size:9px;color:var(--cyan);">企业定制</div>
              <div style="text-align:center;font-size:9px;color:var(--green);">免费+增值</div>
              <div style="text-align:center;font-size:9px;color:var(--yellow);">年度授权</div>
              <div style="text-align:center;font-size:9px;color:var(--cyan);">订阅制</div>
            </div>

          </div>
        </div>
      </div>
    </div>

    <!-- ══════════════════════════════════
         P9 · 未来趋势
    ══════════════════════════════════ -->
    <div class="slide" id="slide-9">
      <div class="s-grid"></div>
      <div style="position:absolute;inset:0;background:radial-gradient(ellipse at 60% 40%, rgba(10,42,90,0.6) 0%, #061529 70%);"></div>
      <div class="s-circle" style="width:350px;height:350px;right:-80px;bottom:-80px;"></div>
      <div class="s-circle" style="width:180px;height:180px;left:-30px;top:50px;opacity:0.4;"></div>
      <div class="s-topbar"></div>
      <div class="s-logo">VMP SEC</div>
      <div class="s-label">07 · FUTURE TRENDS</div>
      <div class="s-title" style="top:28px;">
        技术趋势<span class="hl">展望</span> · VMP的下一个十年
      </div>
      <div class="s-divider" style="top:60px;left:20px;width:200px;"></div>

      <!-- 中心图谱 + 卫星节点 -->
      <div style="position:absolute;top:72px;left:20px;right:20px;bottom:12px;display:flex;gap:12px;">

        <!-- 左:中心图谱 -->
        <div style="width:45%;position:relative;display:flex;align-items:center;justify-content:center;">
          <!-- 外轨道 -->
          <div style="position:absolute;width:260px;height:260px;border-radius:50%;border:1px solid rgba(0,212,255,0.1);"></div>
          <div style="position:absolute;width:190px;height:190px;border-radius:50%;border:1px solid rgba(0,212,255,0.2);"></div>

          <!-- 中心 -->
          <div style="width:90px;height:90px;border-radius:50%;background:linear-gradient(135deg,rgba(0,212,255,0.15),rgba(0,102,204,0.25));border:2px solid rgba(0,212,255,0.5);display:flex;flex-direction:column;align-items:center;justify-content:center;box-shadow:0 0 30px rgba(0,212,255,0.3);z-index:1;text-align:center;">
            <div style="font-size:22px;">🚀</div>
            <div style="font-size:8.5px;font-weight:700;color:var(--cyan);margin-top:3px;">VMP 未来</div>
          </div>

          <!-- 卫星节点 -->
          <div style="position:absolute;top:12px;left:50%;transform:translateX(-50%);">
            <div style="background:rgba(0,212,255,0.15);border:1px solid rgba(0,212,255,0.4);border-radius:20px;padding:4px 10px;font-size:8.5px;color:var(--cyan);white-space:nowrap;">AI驱动混淆</div>
          </div>
          <div style="position:absolute;top:30px;right:5px;">
            <div style="background:rgba(255,140,0,0.15);border:1px solid rgba(255,140,0,0.4);border-radius:20px;padding:4px 10px;font-size:8.5px;color:var(--orange);white-space:nowrap;">硬件可信执行</div>
          </div>
          <div style="position:absolute;bottom:30px;right:5px;">
            <div style="background:rgba(0,255,136,0.12);border:1px solid rgba(0,255,136,0.4);border-radius:20px;padding:4px 10px;font-size:8.5px;color:var(--green);white-space:nowrap;">云端VM引擎</div>
          </div>
          <div style="position:absolute;bottom:12px;left:50%;transform:translateX(-50%);">
            <div style="background:rgba(255,215,0,0.12);border:1px solid rgba(255,215,0,0.4);border-radius:20px;padding:4px 10px;font-size:8.5px;color:var(--yellow);white-space:nowrap;">量子抗性算法</div>
          </div>
          <div style="position:absolute;top:30px;left:5px;">
            <div style="background:rgba(170,68,255,0.15);border:1px solid rgba(170,68,255,0.4);border-radius:20px;padding:4px 10px;font-size:8.5px;color:#aa44ff;white-space:nowrap;">自适应混淆</div>
          </div>
          <div style="position:absolute;bottom:30px;left:5px;">
            <div style="background:rgba(255,68,136,0.12);border:1px solid rgba(255,68,136,0.4);border-radius:20px;padding:4px 10px;font-size:8.5px;color:#ff4488;white-space:nowrap;">跨架构保护</div>
          </div>
        </div>

        <!-- 右:趋势卡片列表 -->
        <div style="flex:1;display:flex;flex-direction:column;gap:9px;">

          <div style="background:var(--bg2);border:1px solid var(--border);border-radius:8px;padding:12px;position:relative;overflow:hidden;flex:1;">
            <div style="position:absolute;left:0;top:0;bottom:0;width:3px;background:var(--cyan);"></div>
            <div style="margin-left:8px;display:flex;gap:10px;align-items:flex-start;">
              <div style="font-size:20px;flex-shrink:0;">🤖</div>
              <div>
                <div style="font-size:11.5px;font-weight:700;color:var(--white);margin-bottom:3px;">AI 生成混淆</div>
                <div style="font-size:9.5px;color:var(--gray);line-height:1.55;">利用大语言模型生成语义等价但结构迥异的混淆代码,使静态分析工具无法建立有效规则库,实现对抗自动化分析工具的混淆策略。</div>
              </div>
            </div>
          </div>

          <div style="background:var(--bg2);border:1px solid var(--border);border-radius:8px;padding:12px;position:relative;overflow:hidden;flex:1;">
            <div style="position:absolute;left:0;top:0;bottom:0;width:3px;background:var(--orange);"></div>
            <div style="margin-left:8px;display:flex;gap:10px;align-items:flex-start;">
              <div style="font-size:20px;flex-shrink:0;">🔒</div>
              <div>
                <div style="font-size:11.5px;font-weight:700;color:var(--white);margin-bottom:3px;">TEE 可信执行环境</div>
                <div style="font-size:9.5px;color:var(--gray);line-height:1.55;">将VM引擎核心移入ARM TrustZone/TEE,核心算法在安全世界执行,普通世界无法访问内存,形成硬件级保护屏障。</div>
              </div>
            </div>
          </div>

          <div style="background:var(--bg2);border:1px solid var(--border);border-radius:8px;padding:12px;position:relative;overflow:hidden;flex:1;">
            <div style="position:absolute;left:0;top:0;bottom:0;width:3px;background:var(--green);"></div>
            <div style="margin-left:8px;display:flex;gap:10px;align-items:flex-start;">
              <div style="font-size:20px;flex-shrink:0;">☁️</div>
              <div>
                <div style="font-size:11.5px;font-weight:700;color:var(--white);margin-bottom:3px;">云端 VM 执行</div>
                <div style="font-size:9.5px;color:var(--gray);line-height:1.55;">核心算法逻辑在云端服务器的VM中执行,本地仅传入参数接收结果,代码永不落地,彻底消除本地逆向风险。</div>
              </div>
            </div>
          </div>

          <div style="background:var(--bg2);border:1px solid var(--border);border-radius:8px;padding:12px;position:relative;overflow:hidden;flex:1;">
            <div style="position:absolute;left:0;top:0;bottom:0;width:3px;background:var(--yellow);"></div>
            <div style="margin-left:8px;display:flex;gap:10px;align-items:flex-start;">
              <div style="font-size:20px;flex-shrink:0;">⚛️</div>
              <div>
                <div style="font-size:11.5px;font-weight:700;color:var(--white);margin-bottom:3px;">量子抗性密码学</div>
                <div style="font-size:9.5px;color:var(--gray);line-height:1.55;">将VM字节码加密方案从AES/RSA迁移至格密码(Lattice-based),抵御量子计算机对现有加密算法的威胁,面向未来十年安全架构。</div>
              </div>
            </div>
          </div>

        </div>
      </div>
    </div>

    <!-- ══════════════════════════════════
         P10 · 封底
    ══════════════════════════════════ -->
    <div class="slide" id="slide-10">
      <!-- 背景 -->
      <div class="s-grid"></div>
      <div style="position:absolute;inset:0;background:radial-gradient(ellipse at 50% 40%, rgba(0,60,120,0.6) 0%, #061529 65%);"></div>
      <!-- 多层装饰圆 -->
      <div style="position:absolute;width:500px;height:500px;border-radius:50%;border:1px solid rgba(0,212,255,0.05);top:50%;left:50%;transform:translate(-50%,-50%);"></div>
      <div style="position:absolute;width:380px;height:380px;border-radius:50%;border:1px solid rgba(0,212,255,0.08);top:50%;left:50%;transform:translate(-50%,-50%);"></div>
      <div style="position:absolute;width:260px;height:260px;border-radius:50%;border:1px solid rgba(0,212,255,0.12);top:50%;left:50%;transform:translate(-50%,-50%);"></div>
      <!-- 装饰角落圆 -->
      <div class="s-circle" style="width:200px;height:200px;left:-40px;bottom:-40px;opacity:0.7;"></div>
      <div class="s-circle" style="width:160px;height:160px;right:-30px;top:-30px;opacity:0.5;"></div>

      <div class="s-topbar"></div>
      <div class="s-logo">VMP SEC</div>

      <!-- 中央内容 -->
      <div style="position:absolute;inset:0;display:flex;flex-direction:column;align-items:center;justify-content:center;text-align:center;padding:20px;">

        <!-- 盾牌图标 -->
        <div style="width:70px;height:70px;border-radius:50%;background:linear-gradient(135deg,rgba(0,212,255,0.2),rgba(0,102,204,0.3));border:2px solid rgba(0,212,255,0.4);display:flex;align-items:center;justify-content:center;font-size:28px;margin-bottom:20px;box-shadow:0 0 30px rgba(0,212,255,0.3),0 0 60px rgba(0,100,200,0.2);">🛡️</div>

        <div style="font-size:11px;letter-spacing:3px;color:var(--cyan);text-transform:uppercase;margin-bottom:12px;">安全是永恒的使命</div>

        <div style="font-size:40px;font-weight:900;background:linear-gradient(135deg,#00d4ff,#e8f4ff,#00a8cc);-webkit-background-clip:text;-webkit-text-fill-color:transparent;text-shadow:none;line-height:1.2;margin-bottom:8px;">
          守护代码安全
        </div>
        <div style="font-size:16px;font-weight:700;color:var(--white);margin-bottom:20px;opacity:0.8;">
          持续攻防 · 不断进化
        </div>

        <div style="width:80px;height:2px;background:linear-gradient(90deg,transparent,var(--cyan),transparent);margin-bottom:24px;"></div>

        <!-- 关键数据行 -->
        <div style="display:flex;gap:32px;margin-bottom:28px;">
          <div style="text-align:center;">
            <div style="font-size:26px;font-weight:900;color:var(--yellow);text-shadow:0 0 20px rgba(255,215,0,0.8);">99%</div>
            <div style="font-size:9px;color:var(--gray);margin-top:2px;">逆向分析阻断率</div>
          </div>
          <div style="width:1px;background:rgba(0,212,255,0.2);"></div>
          <div style="text-align:center;">
            <div style="font-size:26px;font-weight:900;color:var(--cyan);text-shadow:0 0 20px rgba(0,212,255,0.8);">3x</div>
            <div style="font-size:9px;color:var(--gray);margin-top:2px;">攻击成本提升</div>
          </div>
          <div style="width:1px;background:rgba(0,212,255,0.2);"></div>
          <div style="text-align:center;">
            <div style="font-size:26px;font-weight:900;color:var(--green);text-shadow:0 0 20px rgba(0,255,136,0.8);">24/7</div>
            <div style="font-size:9px;color:var(--gray);margin-top:2px;">全天候安全监测</div>
          </div>
        </div>

        <!-- 联系信息 -->
        <div style="background:rgba(10,31,61,0.8);border:1px solid rgba(0,212,255,0.2);border-radius:10px;padding:12px 30px;display:flex;gap:24px;align-items:center;">
          <div style="text-align:center;">
            <div style="font-size:9px;color:var(--gray);margin-bottom:2px;">研究团队</div>
            <div style="font-size:10.5px;color:var(--white);font-weight:600;">移动安全实验室</div>
          </div>
          <div style="width:1px;height:30px;background:rgba(0,212,255,0.2);"></div>
          <div style="text-align:center;">
            <div style="font-size:9px;color:var(--gray);margin-bottom:2px;">专业领域</div>
            <div style="font-size:10.5px;color:var(--white);font-weight:600;">Android · iOS · VMP · 加固</div>
          </div>
          <div style="width:1px;height:30px;background:rgba(0,212,255,0.2);"></div>
          <div style="text-align:center;">
            <div style="font-size:9px;color:var(--gray);margin-bottom:2px;">发布时间</div>
            <div style="font-size:10.5px;color:var(--white);font-weight:600;">2025 · 06</div>
          </div>
        </div>
      </div>

      <!-- 底部版权 -->
      <div style="position:absolute;bottom:10px;left:0;right:0;text-align:center;font-size:8.5px;color:rgba(122,176,212,0.4);">
        本报告内容仅供安全研究与学习参考 &nbsp;|&nbsp; Android VMP 加固技术深度解析
      </div>
    </div>

  </div><!-- /stage -->
</div><!-- /stage-wrap -->

<!-- 圆点导航 -->
<div class="dots-bar" id="dotsBar"></div>

<!-- Toast -->
<div class="toast" id="toast"></div>

<script>
// ══════════════════════════════════
//  PPT 控制器
// ══════════════════════════════════
const TOTAL = 10;
let cur = 1;

const $  = id => document.getElementById(id);
const slides  = () => document.querySelectorAll('.slide');
const allDots = () => document.querySelectorAll('.dot');

// 初始化圆点
function initDots() {
  const bar = $('dotsBar');
  bar.innerHTML = '';
  for (let i = 1; i <= TOTAL; i++) {
    const d = document.createElement('div');
    d.className = 'dot' + (i === 1 ? ' active' : '');
    d.onclick = () => goTo(i);
    bar.appendChild(d);
  }
}

function goTo(n) {
  if (n < 1 || n > TOTAL || n === cur) return;
  slides().forEach(s => { s.classList.remove('active'); });
  cur = n;
  $('slide-' + cur).classList.add('active');
  allDots().forEach((d, i) => d.classList.toggle('active', i + 1 === cur));
  $('pageIndicator').textContent = cur + ' / ' + TOTAL;
  $('progressBar').style.width = (cur / TOTAL * 100) + '%';
}

$('btnPrev').onclick = () => goTo(cur - 1);
$('btnNext').onclick = () => goTo(cur + 1);

// 键盘
document.addEventListener('keydown', e => {
  if (e.key === 'ArrowRight' || e.key === 'ArrowDown') goTo(cur + 1);
  if (e.key === 'ArrowLeft'  || e.key === 'ArrowUp')   goTo(cur - 1);
});

// 触摸滑动
let tx = 0;
const stage = $('stage');
stage.addEventListener('touchstart', e => { tx = e.touches[0].clientX; });
stage.addEventListener('touchend', e => {
  const dx = e.changedTouches[0].clientX - tx;
  if (Math.abs(dx) > 40) { dx < 0 ? goTo(cur + 1) : goTo(cur - 1); }
});

// Toast
function showToast(msg, type = 'info', dur = 3000) {
  const t = $('toast');
  t.textContent = msg;
  t.className = 'toast ' + type + ' show';
  clearTimeout(t._t);
  t._t = setTimeout(() => t.classList.remove('show'), dur);
}

initDots();

// ══════════════════════════════════
//  PPTX 导出
// ══════════════════════════════════
let pptxReady = false;

function loadScript(src) {
  return new Promise((res, rej) => {
    const s = document.createElement('script');
    s.src = src; s.onload = res; s.onerror = rej;
    document.head.appendChild(s);
  });
}

async function ensurePptxGen() {
  if (window.PptxGenJS) return;
  const urls = [
    'https://unpkg.com/pptxgenjs@4.0.1/dist/pptxgen.bundle.js',
    'https://cdn.jsdelivr.net/npm/pptxgenjs@4.0.1/dist/pptxgen.bundle.js'
  ];
  for (const url of urls) {
    try { await loadScript(url); if (window.PptxGenJS) return; } catch(e) {}
  }
  throw new Error('无法加载 PptxGenJS 库');
}

$('btnExport').onclick = async () => {
  showToast('⏳ 正在生成 PPTX,请稍候...', 'info', 30000);
  try {
    await ensurePptxGen();
    buildPptx();
  } catch(e) {
    showToast('❌ 加载失败:' + e.message, 'error');
  }
};

function buildPptx() {
  const pptx = new PptxGenJS();
  pptx.layout = 'LAYOUT_WIDE';
  const W = 13.33, H = 7.5;

  const C = {
    bg:     '061529', bg2:    '0a1f3d', border: '0e3a6e',
    cyan:   '00d4ff', cyan2:  '00a8cc', white:  'e8f4ff',
    gray:   '7ab0d4', green:  '00ff88', orange: 'ff8c00',
    yellow: 'ffd700', dark:   '1a4a8a', red:    'ff4444',
    purple: 'aa44ff', pink:   'ff4488',
  };

  // ── 通用辅助 ──────────────────────────────────
  const addBg      = s => s.addShape(pptx.ShapeType.rect, { x:0,y:0,w:W,h:H, fill:{color:C.bg} });
  const addTopBar  = s => s.addShape(pptx.ShapeType.rect, { x:0,y:0,w:W,h:0.05, fill:{color:C.cyan} });
  const addLogo    = s => s.addText('VMP SEC', { x:W-1.4,y:0.1,w:1.2,h:0.25, fontSize:9,bold:true,color:C.cyan,align:'center',fontFace:'Microsoft YaHei',charSpacing:1.5 });
  const addLabel   = (s,txt) => s.addText(txt, { x:0.4,y:0.12,w:6,h:0.22, fontSize:8,bold:true,color:C.cyan,charSpacing:2.5,fontFace:'Microsoft YaHei' });
  const addTitle   = (s,parts,y=0.38) => s.addText(parts, { x:0.4,y,w:10,h:0.5, fontSize:20,bold:true,fontFace:'Microsoft YaHei' });
  const addCard    = (s,x,y,w,h,fill=C.bg2,brd=C.border) =>
    s.addShape(pptx.ShapeType.roundRect, { x,y,w,h, fill:{color:fill}, line:{color:brd,pt:1}, rectRadius:0.08 });
  const addGlow    = (s,x,y,sz,col=C.dark) =>
    s.addShape(pptx.ShapeType.ellipse, { x,y,w:sz,h:sz, fill:{color:col,transparency:65}, line:{color:col,pt:0} });
  const addDivider = (s,x,y,w) =>
    s.addShape(pptx.ShapeType.rect, { x,y,w,h:0.01, fill:{color:C.cyan,transparency:60} });
  const addProgBar = (s,x,y,w,pct,col=C.cyan) => {
    s.addShape(pptx.ShapeType.rect,{x,y,w,h:0.12,fill:{color:'1a3a5c'},line:{color:C.border,pt:1}});
    s.addShape(pptx.ShapeType.rect,{x,y,w:w*pct,h:0.12,fill:{color:col},line:{color:col,pt:0}});
  };
  const addDot = (s,x,y,sz,col=C.cyan) =>
    s.addShape(pptx.ShapeType.ellipse,{x,y,w:sz,h:sz,fill:{color:col},line:{color:col,pt:0}});
  const addVBar= (s,x,y,h,col=C.cyan) =>
    s.addShape(pptx.ShapeType.rect,{x,y,w:0.04,h,fill:{color:col},line:{color:col,pt:0}});
  const gridBg = (s) => {
    for(let i=0;i<20;i++) s.addShape(pptx.ShapeType.rect,{x:0,y:i*0.4,w:W,h:0.01,fill:{color:C.cyan,transparency:92},line:{color:C.cyan,pt:0}});
    for(let i=0;i<35;i++) s.addShape(pptx.ShapeType.rect,{x:i*0.4,y:0,w:0.01,h:H,fill:{color:C.cyan,transparency:92},line:{color:C.cyan,pt:0}});
  };

  // ══════════════════════════════════
  // P1 · 封面
  // ══════════════════════════════════
  {
    const s = pptx.addSlide();
    addBg(s); gridBg(s);
    addGlow(s, W-3.5,-1,4.5,'0a2a5a');
    addGlow(s,-1.5,-0.5,2.5,C.dark);
    addTopBar(s); addLogo(s);
    // 右侧装饰圆
    s.addShape(pptx.ShapeType.ellipse,{x:W-3.6,y:1.2,w:3.2,h:3.2,fill:{color:C.dark,transparency:70},line:{color:C.cyan,pt:1,transparency:70}});
    s.addShape(pptx.ShapeType.ellipse,{x:W-3.0,y:1.8,w:2.0,h:2.0,fill:{color:C.bg2,transparency:50},line:{color:C.cyan,pt:1,transparency:50}});
    s.addShape(pptx.ShapeType.ellipse,{x:W-2.5,y:2.3,w:1.0,h:1.0,fill:{color:C.cyan,transparency:70},line:{color:C.cyan,pt:1}});
    addDot(s,W-2.1,1.6,0.12,C.cyan);
    addDot(s,W-1.4,2.8,0.09,C.orange);
    addDot(s,W-3.2,3.4,0.09,C.green);
    // Badge
    s.addShape(pptx.ShapeType.roundRect,{x:0.5,y:1.3,w:3.0,h:0.28,fill:{color:C.dark,transparency:50},line:{color:C.cyan,pt:1},rectRadius:0.14});
    s.addText('ANDROID SECURITY · 2025',{x:0.5,y:1.3,w:3.0,h:0.28,fontSize:8,bold:true,color:C.cyan,align:'center',charSpacing:2,fontFace:'Microsoft YaHei'});
    // 主标题
    s.addText([{text:'安卓 VMP\n虚拟机保护加固',options:{color:C.cyan}}],{x:0.5,y:1.7,w:7.5,h:1.6,fontSize:40,bold:true,fontFace:'Microsoft YaHei',lineSpacingMultiple:1.2});
    // 副标题
    s.addText('Virtual Machine Protection · 深度技术解析',{x:0.5,y:3.5,w:7,h:0.35,fontSize:13,color:C.gray,fontFace:'Microsoft YaHei'});
    s.addText('字节码虚拟化 · 指令混淆 · 反调试对抗',{x:0.5,y:3.85,w:7,h:0.32,fontSize:12,color:C.gray,fontFace:'Microsoft YaHei'});
    // 分隔线
    s.addShape(pptx.ShapeType.rect,{x:0.5,y:4.28,w:0.7,h:0.04,fill:{color:C.cyan},line:{color:C.cyan,pt:0}});
    // 底部信息
    s.addText('安全研究团队  |  移动安全实验室  |  2025.06',{x:0.5,y:4.5,w:7,h:0.28,fontSize:10,color:C.gray,fontFace:'Microsoft YaHei'});
    // 底部横条
    s.addShape(pptx.ShapeType.rect,{x:0,y:H-0.04,w:W,h:0.04,fill:{color:C.cyan,transparency:70},line:{color:C.cyan,pt:0}});
  }

  // ══════════════════════════════════
  // P2 · 目录
  // ══════════════════════════════════
  {
    const s = pptx.addSlide();
    addBg(s); gridBg(s);
    addGlow(s,W-2.5,-0.5,3.5,C.dark);
    addTopBar(s); addLogo(s);
    // 左侧青蓝栏
    s.addShape(pptx.ShapeType.rect,{x:0,y:0,w:2.5,h:H,fill:{color:'081a33'},line:{color:C.border,pt:1}});
    s.addShape(pptx.ShapeType.rect,{x:0,y:0,w:0.06,h:H,fill:{color:C.cyan},line:{color:C.cyan,pt:0}});
    s.addText('CONTENTS',{x:0.2,y:1.5,w:2.1,h:0.25,fontSize:8,bold:true,color:C.cyan,charSpacing:3,fontFace:'Microsoft YaHei'});
    s.addText([{text:'目录',options:{color:C.white}},{text:'\n索引',options:{color:C.cyan}}],{x:0.2,y:1.85,w:2.1,h:1.0,fontSize:28,bold:true,fontFace:'Microsoft YaHei',lineSpacingMultiple:1.2});
    s.addShape(pptx.ShapeType.rect,{x:0.2,y:3.0,w:0.5,h:0.05,fill:{color:C.cyan},line:{color:C.cyan,pt:0}});
    s.addText('共 10 个核心章节\n覆盖VMP全技术栈',{x:0.2,y:3.2,w:2.1,h:0.6,fontSize:9.5,color:C.gray,fontFace:'Microsoft YaHei',lineSpacingMultiple:1.4});

    // 目录项数据
    const items = [
      {n:'01',t:'VMP技术概述',d:'虚拟机保护的起源与发展',col:C.cyan},
      {n:'02',t:'核心技术架构',d:'字节码转换与虚拟指令集设计',col:C.orange},
      {n:'03',t:'保护能力矩阵',d:'多层防护机制与反调试对抗',col:C.green},
      {n:'04',t:'性能影响分析',d:'加固前后性能对比与优化方案',col:C.yellow},
      {n:'05',t:'攻防对抗实践',d:'脱壳技术与防御升级策略',col:C.purple},
      {n:'06',t:'行业应用与展望',d:'主流方案对比与未来技术趋势',col:C.pink},
    ];
    const sx = 2.7, sy = 0.7, sh = 0.88, gap = 0.04;
    items.forEach((it, i) => {
      const y = sy + i*(sh+gap);
      addCard(s,sx,y,W-sx-0.3,sh);
      s.addShape(pptx.ShapeType.roundRect,{x:sx+0.12,y:y+0.2,w:0.32,h:0.32,fill:{color:it.col,transparency:30},line:{color:it.col,pt:0},rectRadius:0.05});
      s.addText(it.n,{x:sx+0.12,y:y+0.2,w:0.32,h:0.32,fontSize:9,bold:true,color:C.white,align:'center',fontFace:'Microsoft YaHei'});
      s.addText(it.t,{x:sx+0.55,y:y+0.14,w:W-sx-1.2,h:0.28,fontSize:11,bold:true,color:C.white,fontFace:'Microsoft YaHei'});
      s.addText(it.d,{x:sx+0.55,y:y+0.44,w:W-sx-1.2,h:0.24,fontSize:9,color:C.gray,fontFace:'Microsoft YaHei'});
      s.addText('',{x:W-0.6,y:y+0.2,w:0.3,h:0.32,fontSize:16,color:C.cyan,align:'center',fontFace:'Microsoft YaHei'});
    });
  }

  // ══════════════════════════════════
  // P3 · VMP概述
  // ══════════════════════════════════
  {
    const s = pptx.addSlide();
    addBg(s); gridBg(s);
    addGlow(s,W-3,-1,3.5,C.dark);
    addTopBar(s); addLogo(s);
    addLabel(s,'01 · VMP OVERVIEW');
    addTitle(s,[{text:'VMP 技术',options:{color:C.white}},{text:'概述',options:{color:C.cyan}},{text:' · 什么是虚拟机保护',options:{color:C.white}}]);
    addDivider(s,0.4,0.92,2.5);

    // 左侧说明卡
    const lx=0.36,ly=1.05,lw=5.8,lh=6.0;
    addCard(s,lx,ly,lw,lh,'081a33');
    addVBar(s,lx,ly,lh,C.cyan);
    // 图标区
    s.addShape(pptx.ShapeType.roundRect,{x:lx+0.15,y:ly+0.2,w:0.55,h:0.55,fill:{color:C.dark,transparency:30},line:{color:C.cyan,pt:1},rectRadius:0.08});
    s.addText('🔐',{x:lx+0.15,y:ly+0.2,w:0.55,h:0.55,fontSize:20,align:'center',fontFace:'Microsoft YaHei'});
    s.addText('VMP 核心定义',{x:lx+0.85,y:ly+0.22,w:4.5,h:0.25,fontSize:12,bold:true,color:C.white,fontFace:'Microsoft YaHei'});
    s.addText('VIRTUAL MACHINE PROTECTION',{x:lx+0.85,y:ly+0.48,w:4.5,h:0.2,fontSize:8.5,color:C.cyan,charSpacing:1,fontFace:'Microsoft YaHei'});
    s.addText('VMP(虚拟机保护)是将原始代码转换为自定义虚拟指令集,由内置解释器执行,使攻击者无法直接逆向分析真实逻辑的保护技术。',{x:lx+0.15,y:ly+0.85,w:lw-0.3,h:0.7,fontSize:10,color:C.gray,fontFace:'Microsoft YaHei',lineSpacingMultiple:1.4});
    s.addShape(pptx.ShapeType.rect,{x:lx+0.15,y:ly+1.6,w:lw-0.3,h:0.01,fill:{color:C.border,transparency:0},line:{color:C.border,pt:0}});

    // 三大核心
    const coreItems = [
      {n:'',col:C.cyan,t:'字节码虚拟化',d:'Dalvik/ART字节码 → 专有VM指令集,解释器动态执行'},
      {n:'',col:C.orange,t:'指令混淆加密',d:'多态指令、垃圾插入、控制流平坦化'},
      {n:'',col:C.green,t:'运行时保护',d:'反调试、完整性校验、环境检测'},
    ];
    coreItems.forEach((it,i) => {
      const cy = ly+1.8+i*1.2;
      s.addShape(pptx.ShapeType.roundRect,{x:lx+0.15,y:cy,w:0.28,h:0.28,fill:{color:it.col,transparency:70},line:{color:it.col,pt:1},rectRadius:0.04});
      s.addText(it.n,{x:lx+0.15,y:cy,w:0.28,h:0.28,fontSize:10,bold:true,color:it.col,align:'center',fontFace:'Microsoft YaHei'});
      s.addText(it.t,{x:lx+0.55,y:cy,w:lw-0.7,h:0.25,fontSize:11,bold:true,color:C.white,fontFace:'Microsoft YaHei'});
      s.addText(it.d,{x:lx+0.55,y:cy+0.3,w:lw-0.7,h:0.22,fontSize:9.5,color:C.gray,fontFace:'Microsoft YaHei'});
    });

    // 右侧时间轴
    const rx=6.4,ry=1.05,rw=W-rx-0.3;
    s.addText('📅 VMP技术演进时间轴',{x:rx,y:ry,w:rw,h:0.28,fontSize:11,bold:true,color:C.cyan,fontFace:'Microsoft YaHei'});
    // 竖线
    s.addShape(pptx.ShapeType.rect,{x:rx+0.22,y:ry+0.38,w:0.03,h:5.3,fill:{color:C.cyan,transparency:60},line:{color:C.cyan,pt:0}});

    const tlItems = [
      {y:0.38,col:C.cyan, yr:'2008 · 萌芽期',t:'桌面软件VMP技术兴起',d:'VMProtect、Themida等工具出现,PC端代码保护兴起'},
      {y:1.72,col:C.orange,yr:'2013 · 探索期',t:'移动安全需求爆发',d:'Android生态快速扩张,逆向分析威胁显现,初代加固出现'},
      {y:3.06,col:C.green, yr:'2016 · 成熟期',t:'Android VMP技术成熟',d:'腾讯、360等厂商推出商业VMP方案,金融/游戏行业广泛应用'},
      {y:4.40,col:C.yellow,yr:'2023 · 对抗期',t:'AI辅助攻防新格局',d:'基于Frida/OLLVM的自动脱壳 vs AI驱动的智能混淆'},
    ];
    tlItems.forEach(it => {
      addDot(s,rx+0.18,ry+it.y+0.02,0.12,it.col);
      s.addText(it.yr,{x:rx+0.42,y:ry+it.y-0.01,w:rw-0.4,h:0.22,fontSize:9.5,bold:true,color:it.col,fontFace:'Microsoft YaHei'});
      addCard(s,rx+0.42,ry+it.y+0.23,rw-0.42,0.82);
      s.addText(it.t,{x:rx+0.55,y:ry+it.y+0.3,w:rw-0.6,h:0.24,fontSize:10.5,bold:true,color:C.white,fontFace:'Microsoft YaHei'});
      s.addText(it.d,{x:rx+0.55,y:ry+it.y+0.55,w:rw-0.6,h:0.42,fontSize:9,color:C.gray,fontFace:'Microsoft YaHei',lineSpacingMultiple:1.3});
    });
  }

  // ══════════════════════════════════
  // P4 · 核心技术架构
  // ══════════════════════════════════
  {
    const s = pptx.addSlide();
    addBg(s); gridBg(s);
    addGlow(s,-1,-0.5,3,C.dark);
    addTopBar(s); addLogo(s);
    addLabel(s,'02 · CORE ARCHITECTURE');
    addTitle(s,[{text:'核心技术',options:{color:C.white}},{text:'架构',options:{color:C.cyan}},{text:' · 字节码转换与指令集设计',options:{color:C.white}}]);
    addDivider(s,0.4,0.92,2.5);

    // 流程步骤
    const steps = [
      {n:'1',t:'原始 DEX',d:'Dalvik字节码',col:C.cyan},
      {n:'2',t:'指令分析',d:'控制流图构建',col:C.cyan},
      {n:'3',t:'指令映射',d:'自定义VM操作码',col:C.orange},
      {n:'4',t:'加密打包',d:'VM字节码+解释器',col:C.green},
      {n:'5',t:'运行时执行',d:'解释器取指-译码',col:C.yellow},
    ];
    const sw=2.2,sh=1.05,gap=0.1,sy=1.05;
    const totalW=steps.length*sw+(steps.length-1)*(0.35+gap);
    let sx=(W-totalW)/2;
    steps.forEach((st,i) => {
      s.addShape(pptx.ShapeType.roundRect,{x:sx,y:sy,w:sw,h:sh,fill:{color:'0d2640'},line:{color:st.col,pt:1,transparency:40},rectRadius:0.08});
      s.addShape(pptx.ShapeType.ellipse,{x:sx+(sw-0.32)/2,y:sy+0.12,w:0.32,h:0.32,fill:{color:st.col,transparency:20},line:{color:st.col,pt:0}});
      s.addText(st.n,{x:sx+(sw-0.32)/2,y:sy+0.12,w:0.32,h:0.32,fontSize:11,bold:true,color:C.white,align:'center',fontFace:'Microsoft YaHei'});
      s.addText(st.t,{x:sx,y:sy+0.52,w:sw,h:0.25,fontSize:10,bold:true,color:st.col,align:'center',fontFace:'Microsoft YaHei'});
      s.addText(st.d,{x:sx,y:sy+0.76,w:sw,h:0.2,fontSize:8.5,color:C.gray,align:'center',fontFace:'Microsoft YaHei'});
      if(i<steps.length-1) {
        const ax=sx+sw+gap/2;
        s.addShape(pptx.ShapeType.rect,{x:ax,y:sy+sh/2-0.01,w:0.35,h:0.02,fill:{color:st.col},line:{color:st.col,pt:0}});
      }
      sx+=sw+gap+0.35;
    });

    // 三列技术卡片
    const cols = [
      {x:0.36, col:C.cyan,   sub:'VIRTUAL REGISTERS',  icon:'⚙️',  t:'虚拟寄存器组',  d:'模拟真实CPU寄存器,VPC(虚拟PC指针)控制执行流,VSP(虚拟栈指针)管理操作数栈,支持32/64位操作。', code:'VPC → 取指 → 解码\nVSP[n] ← 操作数\nVReg[0..15] 通用寄存器'},
      {x:4.72, col:C.orange, sub:'CUSTOM ISA',          icon:'📋',  t:'自定义指令集',  d:'每次编译随机化操作码映射,同一逻辑不同版本产生完全不同字节序列,有效对抗基于特征的分析工具。',      tags:['随机操作码','多态混淆','加密存储']},
      {x:9.08, col:C.green,  sub:'VM INTERPRETER',      icon:'🔄',  t:'解释器引擎',   d:'Native层高性能解释器,取指→解码→执行循环,通过JNI调用Android系统API,支持异常处理与反射。',          code:'while(running) {\n  op = fetch(VPC++);\n  dispatch(op);\n}'},
    ];
    const cw=4.16,ch=4.58,cy=2.25;
    cols.forEach(col => {
      addCard(s,col.x,cy,cw,ch);
      addVBar(s,col.x,cy,ch,col.col);
      s.addText(col.icon,{x:col.x+0.15,y:cy+0.18,w:0.4,h:0.4,fontSize:18,fontFace:'Microsoft YaHei'});
      s.addText(col.t,{x:col.x+0.15,y:cy+0.65,w:cw-0.25,h:0.28,fontSize:12,bold:true,color:C.white,fontFace:'Microsoft YaHei'});
      s.addText(col.sub,{x:col.x+0.15,y:cy+0.96,w:cw-0.25,h:0.2,fontSize:8.5,color:col.col,charSpacing:1,fontFace:'Microsoft YaHei'});
      s.addText(col.d,{x:col.x+0.15,y:cy+1.2,w:cw-0.25,h:1.3,fontSize:9.5,color:C.gray,fontFace:'Microsoft YaHei',lineSpacingMultiple:1.4});
      if(col.code) {
        s.addShape(pptx.ShapeType.rect,{x:col.x+0.15,y:cy+2.65,w:cw-0.3,h:1.5,fill:{color:'020d1a'},line:{color:C.border,pt:1}});
        s.addText(col.code,{x:col.x+0.2,y:cy+2.72,w:cw-0.4,h:1.4,fontSize:8.5,color:C.green,fontFace:'Courier New',lineSpacingMultiple:1.5});
      }
      if(col.tags) {
        col.tags.forEach((tag,ti) => {
          s.addShape(pptx.ShapeType.roundRect,{x:col.x+0.15+ti*1.3,y:cy+2.65,w:1.2,h:0.28,fill:{color:C.dark,transparency:30},line:{color:C.border,pt:1},rectRadius:0.04});
          s.addText(tag,{x:col.x+0.15+ti*1.3,y:cy+2.65,w:1.2,h:0.28,fontSize:8,color:C.cyan,align:'center',fontFace:'Microsoft YaHei'});
        });
      }
    });
  }

  // ══════════════════════════════════
  // P5 · 保护能力矩阵
  // ══════════════════════════════════
  {
    const s = pptx.addSlide();
    addBg(s); gridBg(s);
    addGlow(s,W-3,H-2,4,C.dark);
    addTopBar(s); addLogo(s);
    addLabel(s,'03 · PROTECTION MATRIX');
    addTitle(s,[{text:'保护能力',options:{color:C.white}},{text:'矩阵',options:{color:C.cyan}},{text:' · 多层防护机制全景',options:{color:C.white}}]);
    addDivider(s,0.4,0.92,2.5);

    const cards = [
      {col:C.cyan,   sub:'CODE OBFUSCATION',  icon:'🌀', t:'代码混淆',   d:'控制流平坦化将清晰的顺序逻辑转化为状态机结构;字符串加密在运行时动态解密;垃圾代码插入增加分析难度。', tags:['控制流平坦化','字符串加密']},
      {col:C.orange, sub:'ANTI-DEBUG',        icon:'🚫', t:'反调试对抗', d:'检测TracerPID、ptrace占坑;监测调试端口4444/5555;时序检测:rdtsc/clock_gettime时间差分析。', tags:['TracerPID检测','时序校验']},
      {col:C.green,  sub:'INTEGRITY CHECK',   icon:'', t:'完整性校验', d:'对DEX/APK/SO文件进行CRC32/SHA256校验;签名验证防止二次打包;内存代码段哈希比对防止篡改。', tags:['CRC32校验','签名验证']},
      {col:C.yellow, sub:'ENV DETECTION',     icon:'🔍', t:'环境检测',   d:'检测Root/Xposed/Magisk框架;识别模拟器特征(QEMU/Genymotion);Hook框架检测:Frida特征扫描。', tags:['Root检测','Frida检测']},
      {col:C.purple, sub:'SO PROTECTION',     icon:'📦', t:'SO文件加固', d:'ELF Section加密;符号表清除;OLLVM编译混淆;自定义linker动态加载;函数粒度加解密。', tags:['ELF加密','OLLVM']},
      {col:C.pink,   sub:'RESOURCE GUARD',    icon:'🎨', t:'资源文件保护',d:'Assets/Res目录加密打包;资源索引混淆;布局文件混淆防UI逆向;Manifest关键信息隐藏。', tags:['资源加密','布局混淆']},
    ];

    const cw=4.14,ch=2.65,gx=0.13,gy=0.12;
    const startX=0.36,startY=1.05;
    cards.forEach((c,i) => {
      const col=i%3,row=Math.floor(i/3);
      const cx=startX+col*(cw+gx),cy=startY+row*(ch+gy);
      addCard(s,cx,cy,cw,ch);
      addVBar(s,cx,cy,ch,c.col);
      // 右侧装饰图标
      s.addShape(pptx.ShapeType.ellipse,{x:cx+cw-0.65,y:cy+0.12,w:0.5,h:0.5,fill:{color:c.col,transparency:80},line:{color:c.col,pt:0}});
      s.addText(c.icon,{x:cx+cw-0.65,y:cy+0.12,w:0.5,h:0.5,fontSize:18,align:'center',fontFace:'Microsoft YaHei'});
      s.addText(c.sub,{x:cx+0.15,y:cy+0.15,w:cw-0.9,h:0.2,fontSize:8,color:c.col,charSpacing:1,fontFace:'Microsoft YaHei'});
      s.addText(c.t,{x:cx+0.15,y:cy+0.38,w:cw-0.25,h:0.28,fontSize:12,bold:true,color:C.white,fontFace:'Microsoft YaHei'});
      s.addText(c.d,{x:cx+0.15,y:cy+0.72,w:cw-0.25,h:1.35,fontSize:9.5,color:C.gray,fontFace:'Microsoft YaHei',lineSpacingMultiple:1.4});
      c.tags.forEach((tag,ti) => {
        s.addShape(pptx.ShapeType.roundRect,{x:cx+0.15+ti*1.38,y:cy+2.15,w:1.28,h:0.26,fill:{color:c.col,transparency:85},line:{color:c.col,pt:1,transparency:50},rectRadius:0.04});
        s.addText(tag,{x:cx+0.15+ti*1.38,y:cy+2.15,w:1.28,h:0.26,fontSize:8.5,color:c.col,align:'center',fontFace:'Microsoft YaHei'});
      });
    });
  }

  // ══════════════════════════════════
  // P6 · 性能分析
  // ══════════════════════════════════
  {
    const s = pptx.addSlide();
    addBg(s); gridBg(s);
    addGlow(s,W-2,H-2,3,C.dark);
    addTopBar(s); addLogo(s);
    addLabel(s,'04 · PERFORMANCE ANALYSIS');
    addTitle(s,[{text:'性能影响',options:{color:C.white}},{text:'分析',options:{color:C.cyan}},{text:' · 加固代价与优化权衡',options:{color:C.white}}]);
    addDivider(s,0.4,0.92,2.5);

    // 左侧进度条卡片
    const lx=0.36,ly=1.08,lw=6.8,lh=6.0;
    addCard(s,lx,ly,lw,lh);
    s.addText('📊 关键性能指标对比(加固前→加固后)',{x:lx+0.15,y:ly+0.18,w:lw-0.3,h:0.3,fontSize:11.5,bold:true,color:C.white,fontFace:'Microsoft YaHei'});

    const bars = [
      {label:'冷启动时间',  val1:0.45,val2:0.61,n1:'820ms', n2:'1108ms', pct:'+35%',pcol:C.yellow,c2:C.orange},
      {label:'VM执行效率',  val1:0.90,val2:0.36,n1:'100%',  n2:'40%',    pct:'-60%',pcol:C.orange,c2:'ff4444'},
      {label:'APK包体积',   val1:0.40,val2:0.56,n1:'~20MB', n2:'~28MB',  pct:'+40%',pcol:C.cyan,  c2:C.cyan},
      {label:'运行内存',    val1:0.50,val2:0.60,n1:'120MB', n2:'144MB',  pct:'+20%',pcol:C.yellow,c2:C.yellow},
    ];
    bars.forEach((b,i) => {
      const by=ly+0.68+i*1.3;
      s.addText(b.label,{x:lx+0.15,y:by,w:2.5,h:0.25,fontSize:10.5,color:C.white,fontFace:'Microsoft YaHei'});
      s.addText(b.pct,{x:lx+lw-0.9,y:by-0.04,w:0.7,h:0.35,fontSize:16,bold:true,color:b.pcol,align:'right',fontFace:'Microsoft YaHei'});
      //
      s.addText('',{x:lx+0.15,y:by+0.32,w:0.35,h:0.2,fontSize:9,color:C.gray,fontFace:'Microsoft YaHei'});
      addProgBar(s,lx+0.55,by+0.32,lw-1.1,b.val1,C.green);
      s.addText(b.n1,{x:lx+lw-0.52,y:by+0.32,w:0.48,h:0.2,fontSize:9,color:C.green,fontFace:'Microsoft YaHei'});
      //
      s.addText('',{x:lx+0.15,y:by+0.56,w:0.35,h:0.2,fontSize:9,color:C.gray,fontFace:'Microsoft YaHei'});
      addProgBar(s,lx+0.55,by+0.56,lW-1.1||lw-1.1,b.val2,b.c2);
      s.addText(b.n2,{x:lx+lw-0.52,y:by+0.56,w:0.48,h:0.2,fontSize:9,color:b.pcol,fontFace:'Microsoft YaHei'});
    });

    // 右侧
    const rx=7.35,rw=W-rx-0.3;
    // 数据格
    [[`5-15%`,'核心业务方法\n建议VMP保护比例',C.yellow],[`3~5x`,'VM解释执行\n相对JIT的性能损耗',C.cyan]].forEach((d,i) => {
      const ry=ly+0.1+i*1.55;
      addCard(s,rx,ry,rw,1.35);
      s.addText(d[0],{x:rx,y:ry+0.1,w:rw,h:0.7,fontSize:28,bold:true,color:d[2],align:'center',fontFace:'Microsoft YaHei'});
      s.addText(d[1],{x:rx,y:ry+0.82,w:rw,h:0.45,fontSize:9,color:C.gray,align:'center',fontFace:'Microsoft YaHei',lineSpacingMultiple:1.3});
    });
    // 优化策略
    addCard(s,rx,ly+3.2,rw,3.85);
    addVBar(s,rx,ly+3.2,3.85,C.green);
    s.addText('⚡ 性能优化策略',{x:rx+0.15,y:ly+3.38,w:rw-0.2,h:0.28,fontSize:11,bold:true,color:C.white,fontFace:'Microsoft YaHei'});
    const opts=[
      {col:C.cyan,  t:'精准保护选择',d:'仅对核心支付/密钥算法开启VMP,UI层不加固'},
      {col:C.orange,t:'分级保护策略',d:'高危方法VMP+反调试,普通方法仅做代码混淆'},
      {col:C.green, t:'懒加载解密',  d:'VM字节码按需解密,减少启动时解密开销'},
      {col:C.yellow,t:'解释器性能调优',d:'Threaded dispatch代替switch-case,减少分支预测开销'},
    ];
    opts.forEach((o,i) => {
      const oy=ly+3.8+i*0.72;
      s.addShape(pptx.ShapeType.roundRect,{x:rx+0.15,y:oy+0.04,w:0.22,h:0.22,fill:{color:o.col,transparency:70},line:{color:o.col,pt:1},rectRadius:0.03});
      s.addText('',{x:rx+0.15,y:oy+0.04,w:0.22,h:0.22,fontSize:9,color:o.col,align:'center',fontFace:'Microsoft YaHei'});
      s.addText(o.t,{x:rx+0.44,y:oy,w:rw-0.55,h:0.24,fontSize:10.5,bold:true,color:C.white,fontFace:'Microsoft YaHei'});
      s.addText(o.d,{x:rx+0.44,y:oy+0.26,w:rw-0.55,h:0.4,fontSize:9,color:C.gray,fontFace:'Microsoft YaHei',lineSpacingMultiple:1.2});
    });
  }

  // ══════════════════════════════════
  // P7 · 攻防对抗
  // ══════════════════════════════════
  {
    const s = pptx.addSlide();
    addBg(s); gridBg(s);
    addGlow(s,W-2,H-2,3,'3a0a0a');
    addTopBar(s);
    addLogo(s);
    addLabel(s,'05 · ATTACK & DEFENSE');
    addTitle(s,[{text:'攻防',options:{color:C.white}},{text:'对抗实践',options:{color:C.orange}},{text:' · 脱壳技术与防御升级',options:{color:C.white}}]);
    addDivider(s,0.4,0.92,2.5);

    const colW=5.6,sy=1.08,sh=6.0;

    // 攻击侧
    const atk=[
      {col:C.red,  t:'Frida Hook脱壳',   d:'在DexClassLoader/InMemoryDexClassLoader时机转储内存中已解密的DEX字节码,是目前最常用的脱壳手段',   code:'// Hook DexFile\nJava.use("dalvik.system.DexFile")\n.$init.impl = function(){\n  dumpDex(this);\n}'},
      {col:'ff6644',t:'FART/ART主动调用',d:'修改ART解释器源码,在ExecuteSwitchImpl执行入口处主动调用每个方法,强制触发整体脱壳(FART方案)', tags:['主动调用','内存dump']},
      {col:'ff4488',t:'VMP指令语义分析',  d:'通过动态插桩记录VM解释器执行轨迹,结合符号执行还原VM指令语义,重建控制流图实现部分还原',          tags:['符号执行','轨迹分析']},
    ];
    // 攻击header
    s.addShape(pptx.ShapeType.roundRect,{x:0.36,y:sy,w:colW,h:0.38,fill:{color:'3a0a0a',transparency:30},line:{color:C.red,pt:1,transparency:40},rectRadius:0.06});
    s.addText('⚔️ 攻击方(脱壳者)',{x:0.36,y:sy,w:colW,h:0.38,fontSize:11,bold:true,color:C.red,align:'center',charSpacing:2,fontFace:'Microsoft YaHei'});
    atk.forEach((a,i) => {
      const ay=sy+0.5+i*1.75;
      s.addShape(pptx.ShapeType.roundRect,{x:0.36,y:ay,w:colW,h:1.6,fill:{color:C.bg2},line:{color:a.col,pt:1,transparency:50},rectRadius:0.08});
      addVBar(s,0.36,ay,1.6,a.col);
      s.addText(a.t,{x:0.52,y:ay+0.1,w:colW-0.22,h:0.28,fontSize:11,bold:true,color:a.col,fontFace:'Microsoft YaHei'});
      s.addText(a.d,{x:0.52,y:ay+0.42,w:colW-0.22,h:0.7,fontSize:9.5,color:C.gray,fontFace:'Microsoft YaHei',lineSpacingMultiple:1.4});
      if(a.code) {
        s.addShape(pptx.ShapeType.rect,{x:0.52,y:ay+1.1,w:colW-0.22,h:0.42,fill:{color:'020d1a'},line:{color:C.border,pt:1}});
        s.addText(a.code,{x:0.55,y:ay+1.13,w:colW-0.28,h:0.38,fontSize:7.5,color:'ff9999',fontFace:'Courier New',lineSpacingMultiple:1.3});
      }
      if(a.tags) {
        a.tags.forEach((tag,ti) => {
          s.addShape(pptx.ShapeType.roundRect,{x:0.52+ti*1.5,y:ay+1.25,w:1.35,h:0.24,fill:{color:a.col,transparency:82},line:{color:a.col,pt:1,transparency:50},rectRadius:0.04});
          s.addText(tag,{x:0.52+ti*1.5,y:ay+1.25,w:1.35,h:0.24,fontSize:8.5,color:a.col,align:'center',fontFace:'Microsoft YaHei'});
        });
      }
    });

    // VS中间
    const mx=6.1;
    s.addShape(pptx.ShapeType.rect,{x:mx+0.12,y:sy+0.4,w:0.02,h:sh-0.5,fill:{color:C.cyan,transparency:70},line:{color:C.cyan,pt:0}});
    s.addShape(pptx.ShapeType.ellipse,{x:mx,y:sy+2.7,w:0.38,h:0.38,fill:{color:C.bg2},line:{color:C.cyan,pt:1}});
    s.addText('VS',{x:mx,y:sy+2.7,w:0.38,h:0.38,fontSize:9,bold:true,color:C.white,align:'center',fontFace:'Microsoft YaHei'});

    // 防御侧
    const dx=6.6;
    const def=[
      {col:C.cyan,  t:'Frida检测对抗',  d:'扫描/proc/maps中frida-agent特征;检测frida-server监听端口27042;内存特征扫描检测inline hook痕迹', tags:['端口检测','内存扫描']},
      {col:C.green, t:'函数粒度加解密', d:'方法调用前即时解密,执行完毕立即重新加密覆盖内存,使内存dump工具无法在空闲时获取完整可用DEX',    tags:['即时解密','用后销毁']},
      {col:C.yellow,t:'语义混淆加深',   d:'VM指令集随机化+多态混淆+虚假数据流插入,使符号执行路径爆炸;Handler本身也经OLLVM混淆',          tags:['路径爆炸','双重混淆']},
    ];
    s.addShape(pptx.ShapeType.roundRect,{x:dx,y:sy,w:colW,h:0.38,fill:{color:'0a2a1a',transparency:30},line:{color:C.cyan,pt:1,transparency:40},rectRadius:0.06});
    s.addText('🛡️ 防御方(加固者)',{x:dx,y:sy,w:colW,h:0.38,fontSize:11,bold:true,color:C.cyan,align:'center',charSpacing:2,fontFace:'Microsoft YaHei'});
    def.forEach((d2,i) => {
      const dy=sy+0.5+i*1.75;
      s.addShape(pptx.ShapeType.roundRect,{x:dx,y:dy,w:colW,h:1.6,fill:{color:C.bg2},line:{color:d2.col,pt:1,transparency:50},rectRadius:0.08});
      addVBar(s,dx,dy,1.6,d2.col);
      s.addText(d2.t,{x:dx+0.16,y:dy+0.1,w:colW-0.22,h:0.28,fontSize:11,bold:true,color:d2.col,fontFace:'Microsoft YaHei'});
      s.addText(d2.d,{x:dx+0.16,y:dy+0.42,w:colW-0.22,h:0.8,fontSize:9.5,color:C.gray,fontFace:'Microsoft YaHei',lineSpacingMultiple:1.4});
      d2.tags.forEach((tag,ti) => {
        s.addShape(pptx.ShapeType.roundRect,{x:dx+0.16+ti*1.5,y:dy+1.25,w:1.35,h:0.24,fill:{color:d2.col,transparency:82},line:{color:d2.col,pt:1,transparency:50},rectRadius:0.04});
        s.addText(tag,{x:dx+0.16+ti*1.5,y:dy+1.25,w:1.35,h:0.24,fontSize:8.5,color:d2.col,align:'center',fontFace:'Microsoft YaHei'});
      });
    });
  }

  // ══════════════════════════════════
  // P8 · 方案对比
  // ══════════════════════════════════
  {
    const s = pptx.addSlide();
    addBg(s); gridBg(s);
    addGlow(s,-1,H-2,3,C.dark);
    addTopBar(s); addLogo(s);
    addLabel(s,'06 · SOLUTION COMPARISON');
    addTitle(s,[{text:'主流方案',options:{color:C.white}},{text:'对比',options:{color:C.cyan}},{text:' · 商业加固选型参考',options:{color:C.white}}]);
    addDivider(s,0.4,0.92,2.5);

    // 表格容器
    const tx=0.36,ty=1.08,tw=W-0.72,th=6.0;
    addCard(s,tx,ty,tw,th);

    // 列配置
    const vendors=['腾讯乐固','阿里聚安全','360加固','梆梆安全','网易易盾'];
    const vcols=[C.cyan,C.orange,C.green,C.yellow,C.purple];
    const colW2=(tw-1.8)/5;
    const hdrH=0.72;

    // 表头
    s.addShape(pptx.ShapeType.rect,{x:tx,y:ty,w:tw,h:hdrH,fill:{color:C.dark,transparency:60},line:{color:C.border,pt:0}});
    s.addText('对比维度',{x:tx+0.08,y:ty+0.22,w:1.7,h:0.28,fontSize:9.5,color:C.gray,fontFace:'Microsoft YaHei'});
    vendors.forEach((v,i) => {
      const vx=tx+1.8+i*colW2;
      s.addText(v,{x:vx,y:ty+0.1,w:colW2,h:0.28,fontSize:10,bold:true,color:vcols[i],align:'center',fontFace:'Microsoft YaHei'});
    });

    // 数据行
    const rows = [
      {label:'VMP支持',    data:['','','','','']},
      {label:'保护强度',   data:['★★★★','★★★★','★★★','★★★★★','★★★★']},
      {label:'性能损耗',   data:['+30%','+25%','+35%','+20%','+30%']},
      {label:'SO加固',    data:['','','','⚠️','']},
      {label:'适用场景',   data:['游戏/微信','金融/电商','互联网','企业级','游戏/工具']},
      {label:'收费模式',   data:['按次/订阅','企业定制','免费+增值','年度授权','订阅制']},
    ];
    const rowH=(th-hdrH)/rows.length;
    rows.forEach((row,ri) => {
      const ry=ty+hdrH+ri*rowH;
      if(ri%2===0) s.addShape(pptx.ShapeType.rect,{x:tx,y:ry,w:tw,h:rowH,fill:{color:C.bg,transparency:50},line:{color:C.border,pt:0}});
      s.addShape(pptx.ShapeType.rect,{x:tx,y:ry+rowH-0.01,w:tw,h:0.01,fill:{color:C.border,transparency:60},line:{color:C.border,pt:0}});
      s.addText(row.label,{x:tx+0.1,y:ry+0.18,w:1.6,h:0.28,fontSize:10,color:C.gray,fontFace:'Microsoft YaHei'});
      row.data.forEach((d3,di) => {
        const vx=tx+1.8+di*colW2;
        s.addText(d3,{x:vx,y:ry+0.18,w:colW2,h:0.28,fontSize:10,color:vcols[di],align:'center',fontFace:'Microsoft YaHei'});
      });
    });
  }

  // ══════════════════════════════════
  // P9 · 未来趋势
  // ══════════════════════════════════
  {
    const s = pptx.addSlide();
    addBg(s); gridBg(s);
    addGlow(s,W-3,H-2,4,C.dark);
    addGlow(s,-1,1,2,C.dark);
    addTopBar(s); addLogo(s);
    addLabel(s,'07 · FUTURE TRENDS');
    addTitle(s,[{text:'技术趋势',options:{color:C.white}},{text:'展望',options:{color:C.cyan}},{text:' · VMP的下一个十年',options:{color:C.white}}]);
    addDivider(s,0.4,0.92,2.2);

    // 左侧图谱
    const cx2=3.0,cy2=4.0,r1=1.5,r2=1.1,r0=0.55;
    s.addShape(pptx.ShapeType.ellipse,{x:cx2-r1,y:cy2-r1,w:r1*2,h:r1*2,fill:{color:C.dark,transparency:90},line:{color:C.cyan,pt:1,transparency:80}});
    s.addShape(pptx.ShapeType.ellipse,{x:cx2-r2,y:cy2-r2,w:r2*2,h:r2*2,fill:{color:C.dark,transparency:80},line:{color:C.cyan,pt:1,transparency:60}});
    s.addShape(pptx.ShapeType.ellipse,{x:cx2-r0,y:cy2-r0,w:r0*2,h:r0*2,fill:{color:C.dark,transparency:50},line:{color:C.cyan,pt:2}});
    s.addText('🚀',{x:cx2-r0,y:cy2-r0,w:r0*2,h:r0*2,fontSize:18,align:'center',fontFace:'Microsoft YaHei'});
    s.addText('VMP 未来',{x:cx2-0.6,y:cy2+r0-0.1,w:1.2,h:0.22,fontSize:7.5,bold:true,color:C.cyan,align:'center',fontFace:'Microsoft YaHei'});
    // 卫星标签
    const satellites=[
      {label:'AI驱动混淆',  angle:-90, col:C.cyan},
      {label:'硬件可信执行', angle:-30, col:C.orange},
      {label:'云端VM引擎',  angle:30,  col:C.green},
      {label:'量子抗性算法', angle:90,  col:C.yellow},
      {label:'自适应混淆',  angle:150, col:C.purple},
      {label:'跨架构保护',  angle:-150,col:C.pink},
    ];
    satellites.forEach(sat => {
      const rad=sat.angle*Math.PI/180;
      const sx2=cx2+Math.cos(rad)*r1-0.6;
      const sy2=cy2+Math.sin(rad)*r1-0.15;
      s.addShape(pptx.ShapeType.roundRect,{x:sx2,y:sy2,w:1.2,h:0.3,fill:{color:sat.col,transparency:82},line:{color:sat.col,pt:1,transparency:40},rectRadius:0.15});
      s.addText(sat.label,{x:sx2,y:sy2,w:1.2,h:0.3,fontSize:8.5,color:sat.col,align:'center',fontFace:'Microsoft YaHei'});
    });

    // 右侧趋势卡片
    const trends=[
      {icon:'🤖',col:C.cyan,   t:'AI 生成混淆',    d:'利用大语言模型生成语义等价但结构迥异的混淆代码,使静态分析工具无法建立有效规则库,实现对抗自动化分析工具的混淆策略。'},
      {icon:'🔒',col:C.orange, t:'TEE可信执行环境', d:'将VM引擎核心移入ARM TrustZone/TEE,核心算法在安全世界执行,普通世界无法访问内存,形成硬件级保护屏障。'},
      {icon:'☁️',col:C.green,  t:'云端VM执行',     d:'核心算法逻辑在云端服务器的VM中执行,本地仅传入参数接收结果,代码永不落地,彻底消除本地逆向风险。'},
      {icon:'⚛️',col:C.yellow, t:'量子抗性密码学',  d:'将VM字节码加密从AES/RSA迁移至格密码(Lattice-based),抵御量子计算机对现有加密算法的威胁,面向未来十年安全架构。'},
    ];
    const rx2=6.2,rw2=W-rx2-0.3,ch2=(H-1.25)/trends.length-0.1;
    trends.forEach((t2,i) => {
      const ty2=1.05+i*(ch2+0.1);
      addCard(s,rx2,ty2,rw2,ch2);
      addVBar(s,rx2,ty2,ch2,t2.col);
      s.addText(t2.icon,{x:rx2+0.15,y:ty2+0.1,w:0.38,h:0.38,fontSize:18,fontFace:'Microsoft YaHei'});
      s.addText(t2.t,{x:rx2+0.62,y:ty2+0.1,w:rw2-0.72,h:0.28,fontSize:11.5,bold:true,color:C.white,fontFace:'Microsoft YaHei'});
      s.addText(t2.d,{x:rx2+0.62,y:ty2+0.42,w:rw2-0.72,h:ch2-0.52,fontSize:9.5,color:C.gray,fontFace:'Microsoft YaHei',lineSpacingMultiple:1.4});
    });
  }

  // ══════════════════════════════════
  // P10 · 封底
  // ══════════════════════════════════
  {
    const s = pptx.addSlide();
    addBg(s); gridBg(s);
    // 同心装饰圆
    [[3.2,0.04,5],[2.4,0.06,8],[1.6,0.08,12]].forEach(([r,pt,tp]) => {
      s.addShape(pptx.ShapeType.ellipse,{x:W/2-r,y:H/2-r,w:r*2,h:r*2,fill:{color:C.bg,transparency:100},line:{color:C.cyan,pt,transparency:tp}});
    });
    addGlow(s,-1,H-2,2.5,C.dark);
    addGlow(s,W-1.5,-0.5,2,C.dark);
    addTopBar(s); addLogo(s);

    // 中心内容
    s.addShape(pptx.ShapeType.ellipse,{x:W/2-0.5,y:1.5,w:1.0,h:1.0,fill:{color:C.dark,transparency:50},line:{color:C.cyan,pt:2}});
    s.addText('🛡️',{x:W/2-0.5,y:1.5,w:1.0,h:1.0,fontSize:28,align:'center',fontFace:'Microsoft YaHei'});

    s.addText('安全是永恒的使命',{x:2,y:2.62,w:W-4,h:0.3,fontSize:10,bold:true,color:C.cyan,align:'center',charSpacing:3,fontFace:'Microsoft YaHei'});
    s.addText('守护代码安全',{x:1,y:3.0,w:W-2,h:0.9,fontSize:38,bold:true,color:C.cyan,align:'center',fontFace:'Microsoft YaHei'});
    s.addText('持续攻防 · 不断进化',{x:2,y:3.95,w:W-4,h:0.35,fontSize:14,bold:true,color:C.white,align:'center',fontFace:'Microsoft YaHei'});
    s.addShape(pptx.ShapeType.rect,{x:W/2-0.6,y:4.38,w:1.2,h:0.03,fill:{color:C.cyan,transparency:40},line:{color:C.cyan,pt:0}});

    // 数据
    const stats=[['99%','逆向分析阻断率',C.yellow],['3x','攻击成本提升',C.cyan],['24/7','全天候安全监测',C.green]];
    stats.forEach((st,i) => {
      const sx3=W/2-2.1+i*2.1;
      s.addText(st[0],{x:sx3,y:4.55,w:1.8,h:0.55,fontSize:24,bold:true,color:st[2],align:'center',fontFace:'Microsoft YaHei'});
      s.addText(st[1],{x:sx3,y:5.12,w:1.8,h:0.25,fontSize:8.5,color:C.gray,align:'center',fontFace:'Microsoft YaHei'});
      if(i<2) s.addShape(pptx.ShapeType.rect,{x:sx3+1.8,y:4.62,w:0.01,h:0.65,fill:{color:C.border,transparency:30},line:{color:C.border,pt:0}});
    });

    // 底部信息栏
    s.addShape(pptx.ShapeType.roundRect,{x:W/2-3.5,y:5.5,w:7.0,h:0.85,fill:{color:C.bg2,transparency:20},line:{color:C.border,pt:1},rectRadius:0.08});
    const infos=[['研究团队','移动安全实验室'],['专业领域','Android · iOS · VMP'],['发布时间','2025 · 06']];
    infos.forEach((inf,i) => {
      const ix=W/2-3.5+0.4+i*2.3;
      s.addText(inf[0],{x:ix,y:5.6,w:2.0,h:0.22,fontSize:8.5,color:C.gray,fontFace:'Microsoft YaHei'});
      s.addText(inf[1],{x:ix,y:5.82,w:2.0,h:0.25,fontSize:10,bold:true,color:C.white,fontFace:'Microsoft YaHei'});
      if(i<2) s.addShape(pptx.ShapeType.rect,{x:ix+2.0,y:5.62,w:0.01,h:0.5,fill:{color:C.border,transparency:30},line:{color:C.border,pt:0}});
    });

    s.addText('本报告内容仅供安全研究与学习参考  |  Android VMP 加固技术深度解析',{x:0,y:H-0.25,w:W,h:0.2,fontSize:8,color:C.border,align:'center',fontFace:'Microsoft YaHei'});
  }

  // ── 保存 ──────────────────────────────────
  pptx.writeFile({ fileName: '安卓VMP虚拟机保护加固.pptx' })
    .then(() => showToast('✅ PPTX 已成功导出!', 'success'))
    .catch(e => showToast('❌ 导出失败:' + e.message, 'error'));
}
</script>
</body>
</html>

 

维度特征
形态 单 HTML 文件,内含预览器 + PPTX 导出
技术 纯原生 CSS/JS + pptxgenjs@4.0.1 CDN
风格 Apple 极简(黑白灰 + 毛玻璃 + 圆角)
尺寸 16:9 / LAYOUT_WIDE / 13.33×7.5 英寸
导出核心 用 addShape + addText 逐页 1:1 还原,不截图
一致性 HTML 与 PPTX 同色号、同字号、同布局

 

 

 

 

 

 

 

 

 下面是其他解决方案

通用 HTML → PPTX 转换工具 实现方案


核心难点分析

text
HTML → PPTX 的本质问题:

HTML 是"流式布局 + 样式渲染"
PPTX 是"绝对坐标 + 对象模型"

两者是完全不同的渲染体系
没有任何完美的1:1转换方案

实现路线对比,选择最优方案

text
方案A:截图法        HTML → 截图(Canvas) → 图片插入PPTX
方案B:DOM解析法     HTML → 解析DOM/CSS → 构建PPTX对象  
方案C:无头浏览器法  HTML → Puppeteer截图 → PPTX
方案D:混合法        截图做背景 + DOM提取文字做文本层
方案还原度可编辑性复杂度推荐度
A 截图法 ⭐⭐⭐⭐⭐ ❌ 图片 ✅ 前端首选
B DOM解析 ⭐⭐⭐ ✅ 可编辑 极高 ⚠️ 复杂
C 无头浏览器 ⭐⭐⭐⭐⭐ ❌ 图片 中(需Node) ✅ 后端首选
D 混合法 ⭐⭐⭐⭐ ✅ 部分 ✅ 最佳平衡

完整实现代码(方案A+D混合,纯前端)

HTML
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>通用 HTML → PPTX 转换工具</title>
<!-- 依赖库 -->
<script src="https://cdn.jsdelivr.net/npm/html2canvas@1.4.1/dist/html2canvas.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/pptxgenjs@3.12.0/dist/pptxgen.bundle.js"></script>
<style>
* { margin:0; padding:0; box-sizing:border-box; }
body {
    font-family: 'Microsoft YaHei', sans-serif;
    background: #0f0f1a;
    color: #fff;
    min-height: 100vh;
}

/* ===== 布局 ===== */
.app-layout {
    display: grid;
    grid-template-columns: 380px 1fr;
    grid-template-rows: 60px 1fr;
    height: 100vh;
    overflow: hidden;
}

/* ===== 顶栏 ===== */
.topbar {
    grid-column: 1 / -1;
    background: rgba(255,255,255,0.04);
    border-bottom: 1px solid rgba(255,255,255,0.08);
    display: flex;
    align-items: center;
    padding: 0 24px;
    gap: 16px;
}
.topbar h1 {
    font-size: 18px;
    font-weight: 700;
    background: linear-gradient(90deg,#00f5a0,#00d9f5);
    -webkit-background-clip: text;
    -webkit-text-fill-color: transparent;
    background-clip: text;
}
.topbar .sep { flex:1; }
.badge {
    padding: 3px 10px;
    border-radius: 12px;
    font-size: 11px;
    background: rgba(0,245,160,0.15);
    color: #00f5a0;
    border: 1px solid rgba(0,245,160,0.3);
}

/* ===== 左侧面板 ===== */
.left-panel {
    background: rgba(255,255,255,0.02);
    border-right: 1px solid rgba(255,255,255,0.07);
    display: flex;
    flex-direction: column;
    overflow: hidden;
}

.panel-section {
    padding: 18px 20px;
    border-bottom: 1px solid rgba(255,255,255,0.06);
}
.panel-section h3 {
    font-size: 11px;
    color: rgba(255,255,255,0.35);
    text-transform: uppercase;
    letter-spacing: 1.5px;
    margin-bottom: 14px;
}

/* 输入方式 Tab */
.input-tabs {
    display: flex;
    gap: 6px;
    margin-bottom: 14px;
}
.input-tab {
    flex: 1;
    padding: 7px;
    border-radius: 7px;
    border: 1px solid rgba(255,255,255,0.12);
    background: transparent;
    color: rgba(255,255,255,0.5);
    font-size: 12px;
    cursor: pointer;
    transition: all 0.2s;
    text-align: center;
}
.input-tab.active {
    background: rgba(0,245,160,0.15);
    border-color: rgba(0,245,160,0.4);
    color: #00f5a0;
}

/* 文件拖拽区 */
.drop-zone {
    border: 2px dashed rgba(255,255,255,0.15);
    border-radius: 10px;
    padding: 24px;
    text-align: center;
    cursor: pointer;
    transition: all 0.3s;
    position: relative;
}
.drop-zone:hover, .drop-zone.dragover {
    border-color: rgba(0,245,160,0.5);
    background: rgba(0,245,160,0.05);
}
.drop-zone input[type=file] {
    position: absolute;
    inset: 0;
    opacity: 0;
    cursor: pointer;
}
.drop-icon { font-size: 28px; margin-bottom: 8px; }
.drop-text { font-size: 12px; color: rgba(255,255,255,0.4); }
.drop-hint { font-size: 10px; color: rgba(255,255,255,0.25); margin-top: 4px; }

/* URL输入 */
.url-input-wrap { display: none; }
.url-input-wrap.show { display: flex; gap: 8px; }
.url-input {
    flex: 1;
    background: rgba(255,255,255,0.07);
    border: 1px solid rgba(255,255,255,0.12);
    border-radius: 7px;
    color: #fff;
    padding: 8px 12px;
    font-size: 12px;
    outline: none;
}
.url-input:focus { border-color: rgba(0,245,160,0.4); }
.btn-load {
    padding: 8px 14px;
    background: rgba(0,245,160,0.2);
    border: 1px solid rgba(0,245,160,0.4);
    border-radius: 7px;
    color: #00f5a0;
    font-size: 12px;
    cursor: pointer;
    white-space: nowrap;
}

/* 代码粘贴 */
.code-input-wrap { display: none; }
.code-input-wrap.show { display: block; }
.code-textarea {
    width: 100%;
    height: 100px;
    background: rgba(0,0,0,0.3);
    border: 1px solid rgba(255,255,255,0.12);
    border-radius: 7px;
    color: #ccc;
    padding: 10px;
    font-size: 11px;
    font-family: 'Courier New', monospace;
    resize: none;
    outline: none;
    line-height: 1.5;
}
.code-textarea:focus { border-color: rgba(0,245,160,0.4); }
.btn-parse {
    margin-top: 8px;
    width: 100%;
    padding: 8px;
    background: rgba(0,245,160,0.2);
    border: 1px solid rgba(0,245,160,0.4);
    border-radius: 7px;
    color: #00f5a0;
    font-size: 12px;
    cursor: pointer;
}

/* 幻灯片检测结果 */
.detect-result {
    display: none;
    padding: 10px 14px;
    background: rgba(0,245,160,0.08);
    border: 1px solid rgba(0,245,160,0.2);
    border-radius: 8px;
    font-size: 12px;
    color: #00f5a0;
    margin-top: 10px;
}
.detect-result.show { display: flex; align-items: center; gap: 8px; }

/* 幻灯片缩略图列表 */
.thumbs-wrap {
    flex: 1;
    overflow-y: auto;
    padding: 12px 16px;
}
.thumbs-wrap::-webkit-scrollbar { width: 4px; }
.thumbs-wrap::-webkit-scrollbar-thumb { background: rgba(255,255,255,0.1); border-radius: 2px; }

.thumb-grid {
    display: grid;
    grid-template-columns: repeat(2, 1fr);
    gap: 10px;
}

.slide-thumb {
    border-radius: 8px;
    overflow: hidden;
    border: 2px solid rgba(255,255,255,0.08);
    cursor: pointer;
    transition: all 0.2s;
    position: relative;
    aspect-ratio: 16/9;
    background: #111;
}
.slide-thumb:hover { border-color: rgba(0,245,160,0.4); transform: translateY(-2px); }
.slide-thumb.selected { border-color: #00f5a0; }
.slide-thumb img { width: 100%; height: 100%; object-fit: cover; display: block; }
.slide-thumb .thumb-overlay {
    position: absolute;
    inset: 0;
    background: rgba(0,245,160,0.15);
    display: none;
    align-items: center;
    justify-content: center;
    font-size: 20px;
}
.slide-thumb.selected .thumb-overlay { display: flex; }
.thumb-num {
    position: absolute;
    bottom: 4px;
    right: 6px;
    font-size: 9px;
    color: rgba(255,255,255,0.5);
    background: rgba(0,0,0,0.5);
    padding: 1px 5px;
    border-radius: 3px;
}

.thumbs-placeholder {
    text-align: center;
    padding: 40px 20px;
    color: rgba(255,255,255,0.25);
    font-size: 13px;
}
.thumbs-placeholder .ph-icon { font-size: 36px; margin-bottom: 10px; }

/* 底部操作 */
.bottom-actions {
    padding: 14px 16px;
    border-top: 1px solid rgba(255,255,255,0.07);
    display: flex;
    flex-direction: column;
    gap: 10px;
}

.select-bar {
    display: flex;
    gap: 6px;
    align-items: center;
}
.select-bar span { font-size: 11px; color: rgba(255,255,255,0.35); margin-left: auto; }
.btn-xs {
    padding: 4px 10px;
    border-radius: 5px;
    font-size: 11px;
    cursor: pointer;
    border: 1px solid rgba(255,255,255,0.15);
    background: rgba(255,255,255,0.05);
    color: rgba(255,255,255,0.6);
    transition: all 0.2s;
}
.btn-xs:hover { background: rgba(0,245,160,0.1); border-color: rgba(0,245,160,0.3); color:#00f5a0; }

/* 导出配置 */
.export-cfg {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 8px;
}
.cfg-item { display: flex; flex-direction: column; gap: 4px; }
.cfg-item label { font-size: 10px; color: rgba(255,255,255,0.35); }
.cfg-select, .cfg-input {
    background: rgba(255,255,255,0.06);
    border: 1px solid rgba(255,255,255,0.1);
    border-radius: 6px;
    color: #fff;
    padding: 6px 9px;
    font-size: 11px;
    outline: none;
}
.cfg-select option { background: #1a1a2e; }
.cfg-select:focus, .cfg-input:focus { border-color: rgba(0,245,160,0.4); }

.btn-export {
    width: 100%;
    padding: 13px;
    background: linear-gradient(135deg, #00f5a0, #00d9f5);
    border: none;
    border-radius: 9px;
    font-size: 14px;
    font-weight: 700;
    color: #000;
    cursor: pointer;
    transition: all 0.3s;
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 8px;
}
.btn-export:hover { transform: translateY(-2px); box-shadow: 0 8px 25px rgba(0,245,160,0.35); }
.btn-export:disabled {
    background: rgba(255,255,255,0.08);
    color: rgba(255,255,255,0.25);
    cursor: not-allowed;
    transform: none;
    box-shadow: none;
}

/* ===== 右侧预览区 ===== */
.right-panel {
    display: flex;
    flex-direction: column;
    overflow: hidden;
    background: #0a0a0f;
}

.preview-topbar {
    padding: 0 20px;
    height: 48px;
    border-bottom: 1px solid rgba(255,255,255,0.06);
    display: flex;
    align-items: center;
    gap: 14px;
    flex-shrink: 0;
}
.preview-topbar h3 { font-size: 13px; color: rgba(255,255,255,0.5); font-weight: 500; }
.preview-topbar .sep { flex:1; }
.preview-mode-btns { display: flex; gap: 4px; }
.mode-btn {
    padding: 5px 12px;
    border-radius: 5px;
    font-size: 11px;
    cursor: pointer;
    border: 1px solid rgba(255,255,255,0.1);
    background: transparent;
    color: rgba(255,255,255,0.4);
    transition: all 0.2s;
}
.mode-btn.active {
    background: rgba(0,245,160,0.15);
    border-color: rgba(0,245,160,0.4);
    color: #00f5a0;
}

/* iframe预览 */
.preview-area {
    flex: 1;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    overflow: auto;
    padding: 20px;
    gap: 20px;
}

.preview-frame-wrap {
    width: 100%;
    max-width: 960px;
    position: relative;
    border-radius: 12px;
    overflow: hidden;
    border: 1px solid rgba(255,255,255,0.08);
    box-shadow: 0 20px 60px rgba(0,0,0,0.5);
}
.preview-frame-wrap::before {
    content: '';
    display: block;
    padding-top: 56.25%;
}
.preview-frame-wrap iframe {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    border: none;
    transform-origin: top left;
}

/* 截图预览网格 */
.screenshots-grid {
    display: none;
    width: 100%;
    max-width: 1000px;
    display: none;
    grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
    gap: 14px;
    padding: 20px;
}
.screenshots-grid.show { display: grid; }

.screenshot-card {
    border-radius: 8px;
    overflow: hidden;
    border: 2px solid rgba(255,255,255,0.08);
    transition: all 0.2s;
    background: #111;
}
.screenshot-card:hover { border-color: rgba(0,245,160,0.3); transform: translateY(-3px); }
.screenshot-card img { width: 100%; display: block; }
.screenshot-card .sc-label {
    padding: 6px 10px;
    font-size: 10px;
    color: rgba(255,255,255,0.4);
    background: rgba(0,0,0,0.3);
    border-top: 1px solid rgba(255,255,255,0.06);
}

.preview-empty {
    text-align: center;
    color: rgba(255,255,255,0.2);
}
.preview-empty .pe-icon { font-size: 60px; margin-bottom: 16px; }
.preview-empty h3 { font-size: 16px; margin-bottom: 8px; }
.preview-empty p { font-size: 13px; }

/* ===== 进度弹窗 ===== */
.modal-overlay {
    position: fixed;
    inset: 0;
    background: rgba(0,0,0,0.7);
    display: none;
    align-items: center;
    justify-content: center;
    z-index: 1000;
    backdrop-filter: blur(4px);
}
.modal-overlay.show { display: flex; }
.modal-box {
    background: #1a1a2e;
    border: 1px solid rgba(255,255,255,0.12);
    border-radius: 16px;
    padding: 36px 40px;
    width: 480px;
    max-width: 90vw;
}
.modal-box h3 { font-size: 18px; margin-bottom: 6px; }
.modal-box p { font-size: 13px; color: rgba(255,255,255,0.45); margin-bottom: 24px; }

.prog-bar-bg {
    background: rgba(255,255,255,0.08);
    border-radius: 8px;
    height: 8px;
    overflow: hidden;
    margin-bottom: 12px;
}
.prog-bar-fill {
    height: 100%;
    background: linear-gradient(90deg, #00f5a0, #00d9f5);
    border-radius: 8px;
    width: 0%;
    transition: width 0.3s ease;
    box-shadow: 0 0 10px rgba(0,245,160,0.4);
}
.prog-steps {
    max-height: 180px;
    overflow-y: auto;
    font-size: 12px;
    color: rgba(255,255,255,0.4);
}
.prog-steps::-webkit-scrollbar { width: 3px; }
.prog-steps::-webkit-scrollbar-thumb { background: rgba(255,255,255,0.1); }
.prog-step {
    padding: 3px 0;
    display: flex;
    align-items: center;
    gap: 8px;
    animation: stepIn 0.2s ease;
}
@keyframes stepIn { from { opacity:0; transform: translateX(-8px); } to { opacity:1; transform: none; } }
.prog-step.done { color: #00f5a0; }
.prog-step.active { color: #00d9f5; }
.prog-step.err { color: #ff6b6b; }

.prog-pct {
    font-size: 28px;
    font-weight: 900;
    color: #00f5a0;
    text-align: right;
    margin-bottom: 8px;
    font-family: 'Courier New', monospace;
}

/* ===== 通知 ===== */
.toast {
    position: fixed;
    bottom: 30px;
    left: 50%;
    transform: translateX(-50%) translateY(80px);
    background: #1a1a2e;
    border: 1px solid rgba(0,245,160,0.3);
    border-radius: 10px;
    padding: 12px 24px;
    font-size: 14px;
    color: #00f5a0;
    transition: transform 0.3s ease;
    z-index: 2000;
    white-space: nowrap;
}
.toast.show { transform: translateX(-50%) translateY(0); }
.toast.error { border-color: rgba(255,107,107,0.3); color: #ff6b6b; }
/* 响应式 */
@media (max-width: 900px) {
    .app-layout { grid-template-columns: 1fr; grid-template-rows: 60px auto 1fr; }
    .left-panel { max-height: 50vh; }
}
</style>
</head>
<body>
<div class="app-layout">
    <!-- 顶栏 -->
    <div class="topbar">
        <span style="font-size:22px">🔄</span>
        <h1>HTML → PPTX 通用转换工具</h1>
        <span class="badge">纯前端</span>
        <span class="badge" style="background:rgba(0,217,245,0.15);color:#00d9f5;border-color:rgba(0,217,245,0.3);">html2canvas + PptxGenJS</span>
        <div class="sep"></div>
        <span style="font-size:12px;color:rgba(255,255,255,0.3);">支持任意PPT风格HTML</span>
    </div>
    <!-- 左侧面板 -->
    <div class="left-panel">
        <!-- 输入源 -->
        <div class="panel-section">
            <h3>① 输入 HTML 源</h3>
            <div class="input-tabs">
                <div class="input-tab active" data-tab="file" onclick="switchTab('file')">📁 上传文件</div>
                <div class="input-tab" data-tab="code" onclick="switchTab('code')">📝 粘贴代码</div>
                <div class="input-tab" data-tab="url" onclick="switchTab('url')">🌐 URL加载</div>
            </div>
            <!-- 文件上传 -->
            <div id="tab-file">
                <div class="drop-zone" id="dropZone">
                    <input type="file" accept=".html,.htm" onchange="handleFile(this)">
                    <div class="drop-icon">📄</div>
                    <div class="drop-text">拖拽 HTML 文件到此处</div>
                    <div class="drop-hint">或点击选择文件 · 支持 .html .htm</div>
                </div>
            </div>
            <!-- 代码粘贴 -->
            <div class="code-input-wrap" id="tab-code">
                <textarea class="code-textarea" id="codeInput"
                    placeholder="粘贴 HTML 代码..."></textarea>
                <button class="btn-parse" onclick="parseFromCode()">🔍 解析代码</button>
            </div>
            <!-- URL -->
            <div class="url-input-wrap" id="tab-url">
                <input class="url-input" id="urlInput" placeholder="https://..." type="url">
                <button class="btn-load" onclick="loadFromUrl()">加载</button>
            </div>
            <!-- 检测结果 -->
            <div class="detect-result" id="detectResult">
                <span>🎯</span>
                <span id="detectText">检测到 0 张幻灯片</span>
            </div>
        </div>
        <!-- 幻灯片选择 -->
        <div class="panel-section" style="padding-bottom:10px;">
            <h3>② 选择幻灯片</h3>
            <div class="select-bar">
                <button class="btn-xs" onclick="selectAll()">全选</button>
                <button class="btn-xs" onclick="selectNone()">取消</button>
                <button class="btn-xs" onclick="selectInvert()">反选</button>
                <span id="selCount">0 / 0</span>
            </div>
        </div>
        <!-- 缩略图 -->
        <div class="thumbs-wrap" id="thumbsWrap">
            <div class="thumbs-placeholder">
                <div class="ph-icon">🖼️</div>
                <div>加载HTML后显示幻灯片缩略图</div>
            </div>
        </div>
        <!-- 底部操作 -->
        <div class="bottom-actions">
            <div class="export-cfg">
                <div class="cfg-item">
                    <label>幻灯片尺寸</label>
                    <select class="cfg-select" id="cfgSize">
                        <option value="LAYOUT_WIDE">16:9 宽屏</option>
                        <option value="LAYOUT_4x3">4:3 标准</option>
                    </select>
                </div>
                <div class="cfg-item">
                    <label>截图质量</label>
                    <select class="cfg-select" id="cfgQuality">
                        <option value="2">高质量 (2x)</option>
                        <option value="1.5">中质量 (1.5x)</option>
                        <option value="1">标准 (1x)</option>
                        <option value="3">超清 (3x)</option>
                    </select>
                </div>
                <div class="cfg-item">
                    <label>文件名</label>
                    <input class="cfg-input" id="cfgName" value="presentation" placeholder="文件名">
                </div>
                <div class="cfg-item">
                    <label>内容模式</label>
                    <select class="cfg-select" id="cfgMode">
                        <option value="screenshot">截图模式(高保真)</option>
                        <option value="hybrid">混合模式(可编辑文字)</option>
                    </select>
                </div>
            </div>
            <button class="btn-export" id="exportBtn" onclick="startExport()" disabled>
                <span>⚡</span><span id="exportBtnText">请先加载 HTML</span>
            </button>
        </div>
    </div>
    <!-- 右侧预览 -->
    <div class="right-panel">
        <div class="preview-topbar">
            <h3>📺 预览</h3>
            <div class="sep"></div>
            <div class="preview-mode-btns">
                <button class="mode-btn active" onclick="setPreviewMode('frame')" id="modeFrame">实时预览</button>
                <button class="mode-btn" onclick="setPreviewMode('screenshots')" id="modeShots">截图预览</button>
            </div>
        </div>
        <div class="preview-area" id="previewArea">
            <div class="preview-empty" id="previewEmpty">
                <div class="pe-icon">🖥️</div>
                <h3>等待加载</h3>
                <p>上传 HTML 文件后,这里会显示实时预览</p>
            </div>
            <!-- iframe 预览 -->
            <div class="preview-frame-wrap" id="previewFrameWrap" style="display:none;">
                <iframe id="previewFrame" sandbox="allow-scripts allow-same-origin"></iframe>
            </div>
            <!-- 截图网格 -->
            <div class="screenshots-grid" id="screenshotsGrid"></div>
        </div>
    </div>
</div>
<!-- 进度弹窗 -->
<div class="modal-overlay" id="modalOverlay">
    <div class="modal-box">
        <div class="prog-pct" id="progPct">0%</div>
        <h3 id="progTitle">🔄 正在处理...</h3>
        <p id="progSubtitle">请稍候,正在截图并生成 PPTX</p>
        <div class="prog-bar-bg">
            <div class="prog-bar-fill" id="progFill"></div>
        </div>
        <div class="prog-steps" id="progSteps"></div>
    </div>
</div>
<!-- Toast -->
<div class="toast" id="toast"></div>
<script>
// ================================================================
//  全局状态
// ================================================================
const state = {
    htmlContent: '',       // 原始HTML字符串
    slides: [],            // [{el, index, title, screenshot}]
    selected: new Set(),   // 选中的幻灯片索引
    previewMode: 'frame',  // 'frame' | 'screenshots'
    iframeDoc: null,       // iframe的document引用
    screenshots: [],       // base64截图数组
};
// ================================================================
//  Tab 切换
// ================================================================
function switchTab(name) {
    ['file','code','url'].forEach(t => {
        document.getElementById(`tab-${t}`).style.display = t === name ? 'block' : 'none';
        if (t === 'url') document.getElementById(`tab-${t}`).className =
            'url-input-wrap' + (t === name ? ' show' : '');
    });
    document.querySelectorAll('.input-tab').forEach(btn => {
        btn.classList.toggle('active', btn.dataset.tab === name);
    });
    // 特殊处理
    document.getElementById('tab-url').style.display = name === 'url' ? 'flex' : 'none';
    document.getElementById('tab-code').style.display = name === 'code' ? 'block' : 'none';
    document.getElementById('tab-file').style.display = name === 'file' ? 'block' : 'none';
}
// ================================================================
//  文件处理
// ================================================================
function handleFile(input) {
    const file = input.files[0];
    if (!file) return;
    const reader = new FileReader();
    reader.onload = e => {
        loadHTML(e.target.result, file.name);
    };
    reader.readAsText(file, 'utf-8');
}
function parseFromCode() {
    const code = document.getElementById('codeInput').value.trim();
    if (!code) { showToast('请粘贴 HTML 代码', 'error'); return; }
    loadHTML(code, 'pasted.html');
}
async function loadFromUrl() {
    const url = document.getElementById('urlInput').value.trim();
    if (!url) { showToast('请输入URL', 'error'); return; }
    showToast('⚠️ 跨域限制,仅支持同域或CORS开放的页面');
    try {
        const resp = await fetch(url);
        const html = await resp.text();
        loadHTML(html, 'remote.html');
    } catch(e) {
        showToast('加载失败:' + e.message, 'error');
    }
}
// 拖拽
const dz = document.getElementById('dropZone');
dz.addEventListener('dragover', e => { e.preventDefault(); dz.classList.add('dragover'); });
dz.addEventListener('dragleave', () => dz.classList.remove('dragover'));
dz.addEventListener('drop', e => {
    e.preventDefault();
    dz.classList.remove('dragover');
    const file = e.dataTransfer.files[0];
    if (file && (file.name.endsWith('.html') || file.name.endsWith('.htm'))) {
        const reader = new FileReader();
        reader.onload = ev => loadHTML(ev.target.result, file.name);
        reader.readAsText(file, 'utf-8');
    }
});
// ================================================================
//  核心:加载并解析HTML
// ================================================================
function loadHTML(htmlStr, filename) {
    state.htmlContent = htmlStr;
    state.slides = [];
    state.selected.clear();
    state.screenshots = [];
    // 渲染iframe预览
    const iframe = document.getElementById('previewFrame');
    const blob = new Blob([htmlStr], { type: 'text/html' });
    iframe.src = URL.createObjectURL(blob);
    document.getElementById('previewFrameWrap').style.display = 'block';
    document.getElementById('previewEmpty').style.display = 'none';
    // 等iframe加载完成后检测幻灯片
    iframe.onload = () => {
        try {
            state.iframeDoc = iframe.contentDocument || iframe.contentWindow.document;
            detectSlides(state.iframeDoc, htmlStr);
        } catch(e) {
            // 跨域无法访问,改用DOMParser
            detectSlidesFromString(htmlStr);
        }
    };
    // 更新文件名
    const nameBase = filename.replace(/\.(html|htm)$/i, '');
    document.getElementById('cfgName').value = nameBase;
}
// ================================================================
//  幻灯片检测策略(多策略自动检测)
// ================================================================
function detectSlides(doc, htmlStr) {
    const strategies = [
        // 策略1:查找 .slide 类
        () => Array.from(doc.querySelectorAll('.slide')).filter(el =>
            !el.closest('.slide') || el.parentElement.classList.contains('slides-container')),
        // 策略2:查找 section 标签(Reveal.js)
        () => Array.from(doc.querySelectorAll('section.slide, .slides > section')),
        // 策略3:查找 data-slide 属性
        () => Array.from(doc.querySelectorAll('[data-slide], [data-page]')),
        // 策略4:查找大型直接子块
        () => {
            const container = doc.querySelector('.slides-container, .slideshow, .presentation, #slides');
            return container ? Array.from(container.children) : [];
        },
        // 策略5:查找有固定/绝对定位且全屏的元素
        () => Array.from(doc.querySelectorAll('div,section')).filter(el => {
            const st = window.getComputedStyle ? null : el.style;
            return el.style.position === 'absolute' || el.style.position === 'fixed';
        }),
    ];
    let slides = [];
    for (const strategy of strategies) {
        try {
            slides = strategy();
            if (slides.length > 1) break;
        } catch(e) {}
    }
    // 若全部策略失败,把整个body作为1张幻灯片
    if (slides.length === 0) {
        slides = [doc.body];
    }
    buildSlideList(slides, doc);
}
function detectSlidesFromString(htmlStr) {
    // 无法访问iframe DOM时,用DOMParser解析
    const parser = new DOMParser();
    const doc = parser.parseFromString(htmlStr, 'text/html');
    detectSlides(doc, htmlStr);
}
function buildSlideList(els, doc) {
    state.slides = els.map((el, i) => ({
        el,
        index: i,
        title: extractSlideTitle(el, i),
        screenshot: null,
    }));
    // 默认全选
    state.slides.forEach(s => state.selected.add(s.index));
    // 更新UI
    const total = state.slides.length;
    document.getElementById('detectText').textContent = `检测到 ${total} 张幻灯片`;
    document.getElementById('detectResult').classList.add('show');
    document.getElementById('exportBtn').disabled = false;
    document.getElementById('exportBtnText').textContent = `导出 ${total} 张为 PPTX`;
    updateSelCount();
    renderThumbs();
}
function extractSlideTitle(el, index) {
    // 按优先级提取标题文字
    const titleEl = el.querySelector('h1,h2,h3,.slide-title,.cover-title,.title');
    if (titleEl) {
        return titleEl.textContent.trim().slice(0, 40) || `幻灯片 ${index + 1}`;
    }
    return `幻灯片 ${index + 1}`;
}
// ================================================================
//  缩略图渲染
// ================================================================
function renderThumbs() {
    const wrap = document.getElementById('thumbsWrap');
    if (state.slides.length === 0) {
        wrap.innerHTML = '<div class="thumbs-placeholder"><div class="ph-icon">🖼️</div><div>暂无幻灯片</div></div>';
        return;
    }
    wrap.innerHTML = `<div class="thumb-grid" id="thumbGrid"></div>`;
    const grid = document.getElementById('thumbGrid');
    state.slides.forEach((slide, i) => {
        const div = document.createElement('div');
        div.className = 'slide-thumb selected';
        div.id = `thumb-${i}`;
        div.onclick = () => toggleSlide(i);
        div.innerHTML = `
            <div class="thumb-overlay">✓</div>
            <div class="thumb-num">${String(i+1).padStart(2,'0')}</div>
            <div style="padding:8px;font-size:10px;color:rgba(255,255,255,0.4);height:100%;display:flex;align-items:center;justify-content:center;text-align:center;">
                ${slide.title}
            </div>
        `;
        grid.appendChild(div);
    });
}
function toggleSlide(i) {
    if (state.selected.has(i)) {
        state.selected.delete(i);
        document.getElementById(`thumb-${i}`)?.classList.remove('selected');
    } else {
        state.selected.add(i);
        document.getElementById(`thumb-${i}`)?.classList.add('selected');
    }
    updateSelCount();
}
function selectAll() {
    state.slides.forEach(s => {
        state.selected.add(s.index);
        document.getElementById(`thumb-${s.index}`)?.classList.add('selected');
    });
    updateSelCount();
}
function selectNone() {
    state.slides.forEach(s => {
        state.selected.delete(s.index);
        document.getElementById(`thumb-${s.index}`)?.classList.remove('selected');
    });
    updateSelCount();
}
function selectInvert() {
    state.slides.forEach(s => {
        if (state.selected.has(s.index)) {
            state.selected.delete(s.index);
            document.getElementById(`thumb-${s.index}`)?.classList.remove('selected');
        } else {
            state.selected.add(s.index);
            document.getElementById(`thumb-${s.index}`)?.classList.add('selected');
        }
    });
    updateSelCount();
}
function updateSelCount() {
    document.getElementById('selCount').textContent =
        `${state.selected.size} / ${state.slides.length}`;
}
// ================================================================
//  预览模式
// ================================================================
function setPreviewMode(mode) {
    state.previewMode = mode;
    document.getElementById('modeFrame').classList.toggle('active', mode === 'frame');
    document.getElementById('modeShots').classList.toggle('active', mode === 'screenshots');
    document.getElementById('previewFrameWrap').style.display = mode === 'frame' ? 'block' : 'none';
    const sg = document.getElementById('screenshotsGrid');
    if (mode === 'screenshots') {
        sg.classList.add('show');
        if (state.screenshots.length > 0) renderScreenshotGrid();
        else sg.innerHTML = '<div style="color:rgba(255,255,255,0.3);grid-column:1/-1;text-align:center;padding:40px;">请先导出以生成截图预览</div>';
    } else {
        sg.classList.remove('show');
    }
}
function renderScreenshotGrid() {
    const grid = document.getElementById('screenshotsGrid');
    grid.innerHTML = '';
    state.screenshots.forEach((b64, i) => {
        const card = document.createElement('div');
        card.className = 'screenshot-card';
        card.innerHTML = `
            <img src="${b64}" loading="lazy">
            <div class="sc-label">幻灯片 ${i+1} · ${state.slides[i]?.title || ''}</div>
        `;
        grid.appendChild(card);
    });
}
// ================================================================
//  进度系统
// ================================================================
let progStepsEl, progFillEl, progPctEl;
function showModal(title, subtitle) {
    document.getElementById('modalOverlay').classList.add('show');
    document.getElementById('progTitle').textContent = title;
    document.getElementById('progSubtitle').textContent = subtitle;
    progStepsEl = document.getElementById('progSteps');
    progFillEl = document.getElementById('progFill');
    progPctEl = document.getElementById('progPct');
    progStepsEl.innerHTML = '';
    setProgress(0);
}
function hideModal() { document.getElementById('modalOverlay').classList.remove('show'); }
function setProgress(pct) {
    progFillEl.style.width = pct + '%';
    progPctEl.textContent = Math.round(pct) + '%';
}
function addStep(text, type = 'active') {
    const icons = { done:'✅', active:'⏳', err:'❌' };
    const div = document.createElement('div');
    div.className = `prog-step ${type}`;
    div.textContent = `${icons[type]} ${text}`;
    progStepsEl.appendChild(div);
    progStepsEl.scrollTop = progStepsEl.scrollHeight;
    return div;
}
function markStepDone(el) { el.className = 'prog-step done'; el.textContent = el.textContent.replace('⏳','✅'); }
// ================================================================
//  核心导出流程
// ================================================================
async function startExport() {
    if (state.selected.size === 0) { showToast('请至少选择一张幻灯片', 'error'); return; }
    const mode = document.getElementById('cfgMode').value;
    const scale = parseFloat(document.getElementById('cfgQuality').value);
    const layout = document.getElementById('cfgSize').value;
    const fileName = document.getElementById('cfgName').value || 'presentation';
    showModal('🔄 正在生成 PPTX', `共 ${state.selected.size} 张幻灯片 · ${mode === 'screenshot' ? '截图模式' : '混合模式'}`);
    try {
        const selectedSlides = state.slides.filter(s => state.selected.has(s.index));
        const total = selectedSlides.length;
        state.screenshots = [];
        // Step1: 初始化PPTX
        const s1 = addStep('初始化 PptxGenJS');
        await sleep(100);
        const pptx = new PptxGenJS();
        pptx.layout = layout;
        pptx.title = fileName;
        // 幻灯片尺寸(英寸)
        const W = layout === 'LAYOUT_WIDE' ? 13.33 : 10;
        const H = 7.5;
        markStepDone(s1);
        setProgress(5);
        // Step2: 截图每张幻灯片
        const s2 = addStep(`截图 ${total} 张幻灯片...`);
        for (let i = 0; i < selectedSlides.length; i++) {
            const slideData = selectedSlides[i];
            const pct = 5 + (i / total) * 70;
            setProgress(pct);
            const si = addStep(`截图幻灯片 ${i+1}/${total}: ${slideData.title}`);
            try {
                // 使截幻灯片可见
                const el = slideData.el;
                const origStyle = {
                    opacity: el.style.opacity,
                    transform: el.style.transform,
                    position: el.style.position,
                    zIndex: el.style.zIndex,
                    display: el.style.display,
                };
                // 临时让元素完全可见
                el.style.opacity = '1';
                el.style.transform = 'none';
                el.style.zIndex = '9999';
                // 隐藏其他幻灯片
                if (state.iframeDoc) {
                    Array.from(state.iframeDoc.querySelectorAll('.slide')).forEach(other => {
                        if (other !== el) other.style.visibility = 'hidden';
                    });
                }
                await sleep(50);
                // 使用html2canvas截图
                const targetEl = state.iframeDoc ? state.iframeDoc.body : el;
                const canvas = await html2canvas(targetEl || el, {
                    scale: scale,
                    useCORS: true,
                    allowTaint: true,
                    backgroundColor: '#0a0a0a',
                    logging: false,
                    width: state.iframeDoc?.documentElement?.scrollWidth || el.offsetWidth,
                    height: state.iframeDoc?.documentElement?.scrollHeight || el.offsetHeight,
                    windowWidth: 1280,
                    windowHeight: 720,
                    x: el.offsetLeft || 0,
                    y: el.offsetTop || 0,
                });
                // 恢复可见性
                el.style.opacity = origStyle.opacity;
                el.style.transform = origStyle.transform;
                el.style.zIndex = origStyle.zIndex;
                if (state.iframeDoc) {
                    Array.from(state.iframeDoc.querySelectorAll('.slide')).forEach(other => {
                        other.style.visibility = '';
                    });
                }
                const imgData = canvas.toDataURL('image/jpeg', 0.92);
                state.screenshots.push(imgData);
                slideData.screenshot = imgData;
                // 更新缩略图
                const thumbEl = document.getElementById(`thumb-${slideData.index}`);
                if (thumbEl) {
                    thumbEl.style.backgroundImage = `url(${imgData})`;
                    thumbEl.style.backgroundSize = 'cover';
                    thumbEl.style.backgroundPosition = 'center';
                    const placeholder = thumbEl.querySelector('div:last-child');
                    if (placeholder) placeholder.style.display = 'none';
                }
                markStepDone(si);
                // 向PPTX添加幻灯片
                const pSlide = pptx.addSlide();
                pSlide.addImage({
                    data: imgData,
                    x: 0, y: 0, w: W, h: H,
                    sizing: { type: 'contain', w: W, h: H }
                });
                // 混合模式:额外提取文字
                if (mode === 'hybrid') {
                    extractTextToSlide(pSlide, slideData.el, W, H);
                }
            } catch(err) {
                console.error('截图失败:', err);
                addStep(`幻灯片 ${i+1} 截图失败,尝试备用方案`, 'err');
                // 备用:用纯色背景+文字
                const pSlide = pptx.addSlide();
                pSlide.background = { color: '0A0A1A' };
                pSlide.addText(slideData.title, {
                    x: 0.5, y: H/2 - 0.4, w: W-1, h: 0.8,
                    fontSize: 28, bold: true, color: '00F5A0',
                    align: 'center', fontFace: 'Microsoft YaHei'
                });
                pSlide.addText('(截图生成失败)', {
                    x: 0.5, y: H/2 + 0.5, w: W-1, h: 0.4,
                    fontSize: 14, color: '666666', align: 'center'
                });
                state.screenshots.push(null);
            }
            await sleep(30);
        }
        markStepDone(s2);
        setProgress(80);
        // Step3: 写入文件
        const s3 = addStep('写入 PPTX 文件...');
        await sleep(200);
        await pptx.writeFile({ fileName: `${fileName}.pptx` });
        markStepDone(s3);
        setProgress(100);
        addStep(`🎉 完成!共生成 ${total} 张幻灯片`, 'done');
        // 更新截图预览
        if (state.previewMode === 'screenshots') renderScreenshotGrid();
        await sleep(1000);
        hideModal();
        showToast(`✅ 已生成 ${fileName}.pptx,共 ${total} 张幻灯片`);
    } catch(err) {
        console.error('导出失败:', err);
        addStep('导出失败:' + err.message, 'err');
        await sleep(2000);
        hideModal();
        showToast('导出失败:' + err.message, 'error');
    }
}
// ================================================================
//  混合模式:提取文字层
// ================================================================
function extractTextToSlide(pSlide, el, W, H) {
    if (!el) return;
    // 获取元素尺寸基准(用于坐标换算)
    const elW = el.offsetWidth || 1280;
    const elH = el.offsetHeight || 720;
    const scaleX = W / elW;
    const scaleY = H / elH;
    // 提取所有文本节点
    const textEls = el.querySelectorAll('h1,h2,h3,h4,h5,p,span,li,div');
    textEls.forEach(textEl => {
        const text = textEl.textContent.trim();
        if (!text || text.length < 2) return;
        // 只处理直接有文本的元素(避免重复)
        const hasDirectText = Array.from(textEl.childNodes)
            .some(n => n.nodeType === 3 && n.textContent.trim().length > 1);
        if (!hasDirectText) return;
        try {
            const rect = textEl.getBoundingClientRect();
            const cs = window.getComputedStyle(textEl);
            const fontSize = parseFloat(cs.fontSize) * scaleX * 0.75; // px转pt近似
            const color = cssColorToHex(cs.color) || 'FFFFFF';
            const bold = parseInt(cs.fontWeight) >= 700;
            if (rect.width < 10 || rect.height < 10) return;
            // 坐标转换
            const x = Math.max(0, rect.left * scaleX);
            const y = Math.max(0, rect.top * scaleY);
            const w = Math.min(W - x, rect.width * scaleX);
            const h = Math.min(H - y, rect.height * scaleY);
            if (w < 0.1 || h < 0.1) return;
            pSlide.addText(text, {
                x, y, w, h,
                fontSize: Math.max(6, Math.min(fontSize, 48)),
                color,
                bold,
                fontFace: 'Microsoft YaHei',
                wrap: true,
                transparency: 100, // 透明文字层,只为可编辑/搜索
            });
        } catch(e) {}
    });
}
// CSS颜色 → Hex
function cssColorToHex(cssColor) {
    if (!cssColor) return 'FFFFFF';
    const m = cssColor.match(/rgb\((\d+),\s*(\d+),\s*(\d+)\)/);
    if (!m) return 'FFFFFF';
    return [m[1],m[2],m[3]].map(n => parseInt(n).toString(16).padStart(2,'0')).join('').toUpperCase();
}
// ================================================================
//  通知
// ================================================================
function showToast(msg, type = 'success') {
    const t = document.getElementById('toast');
    t.textContent = msg;
    t.className = `toast ${type === 'error' ? 'error' : ''} show`;
    setTimeout(() => t.classList.remove('show'), 3500);
}
function sleep(ms) { return new Promise(r => setTimeout(r, ms)); }
// ================================================================
//  初始化
// ================================================================
switchTab('file');
</script>
</body>
</html>

架构说明

text
┌─────────────────────────────────────────────────────┐
│              通用HTML→PPTX 核心流程                   │
├─────────────────────────────────────────────────────┤
│                                                     │
│  HTML输入  →  iframe渲染  →  幻灯片检测              │
│    ↓              ↓              ↓                  │
│  文件/代码/URL  实时预览    5种策略自动识别            │
│                                                     │
│  幻灯片检测策略(按优先级):                          │
│  1. .slide 类选择器                                  │
│  2. section标签 (Reveal.js兼容)                      │
│  3. data-slide 属性                                  │
│  4. 容器直接子元素                                    │
│  5. 整个body作为单页                                  │
│                                                     │
│  截图  →  插入PPTX  →  (可选)混合文字层  →  下载   │
│    ↓                                                │
│  html2canvas逐帧渲染                                 │
│  · 临时显示当前幻灯片                                 │
│  · 隐藏其他幻灯片                                     │
│  · 截图后恢复状态                                     │
│                                                     │
└─────────────────────────────────────────────────────┘

两种导出模式对比

 截图模式混合模式
外观保真度 ⭐⭐⭐⭐⭐ ⭐⭐⭐⭐⭐
文字可选中
文字可搜索
文件大小 较大 较大
兼容性 极高

使用的核心库

text
html2canvas  →  将DOM元素渲染为Canvas截图
PptxGenJS    →  在浏览器生成.pptx文件
DOMParser    →  离线解析HTML字符串
 

 

 

 

PPT 能实现的,HTML 基本都能实现,甚至能做得更好!


核心对比

能力PPTHTML/CSS/JS
文字排版
图片/图标
动画过渡 ✅ 有限 ✅ 更强
交互响应 ⚠️ 很弱 ✅ 极强
视频嵌入
实时数据
3D效果 ❌/⚠️ ✅ WebGL
网络请求
代码运行

HTML 超越 PPT 的地方

text
PPT 做不到但 HTML 可以:

✅ 嵌入可运行的代码编辑器
✅ 实时从API拉取数据展示
✅ 粒子特效 / 3D旋转场景
✅ 用户输入交互(表单、游戏)
✅ 任何设备浏览器直接打开
✅ Canvas 绘制动态图表
✅ WebGL 三维渲染

唯一的"例外"

PPT 有一些办公专属功能是 HTML 天然不具备的(但也不是做不到,只是没必要):

  • 📄 直接导出为 .pptx 格式文件
  • 🖨️ 按幻灯片分页打印
  • 🤝 多人实时协同编辑(Google Slides有,HTML需要后端支持)

结论

text
PPT  ⊂  HTML 的能力范围

HTML 是 PPT 的超集
PPT能做的,HTML都能做
HTML能做的,PPT大部分做不到

你想用 HTML 实现什么效果,直接说,我来帮你做!

 

 

 

 

 

## 一、核心思路对比

| 方案 | 样式丰富度 | 实现难度 | 推荐度 |
|------|-----------|---------|--------|
| MD → PPT(python-pptx 裸转) | ⭐ | 低 | ❌ |
| HTML/Reveal.js → PDF/PPT | ⭐⭐⭐⭐ | 中 | ✅ |
| **AI生成结构化JSON → 模板渲染** | ⭐⭐⭐⭐⭐ | 中高 | ✅✅✅ |
| AI直接生成python-pptx代码 | ⭐⭐⭐ | 高 | ⚠️ |

---

## 二、推荐方案:结构化DSL + 模板引擎(三层架构)

```
┌──────────────────────────────────────────────────┐
│ Layer 1: 内容生成层(LLM节点) │
│ 用户需求 → 大纲 → 每页结构化JSON │
├──────────────────────────────────────────────────┤
│ Layer 2: 版式选择层(规则/LLM) │
│ 根据内容类型匹配最佳版式模板 │
├──────────────────────────────────────────────────┤
│ Layer 3: 渲染层(HTML模板 + 转换工具) │
│ Jinja2 → HTML/CSS → PPTX │
└──────────────────────────────────────────────────┘
```

### 2.1 工作流节点设计(在你的Dify-like平台中)

```
[输入主题]
→ [LLM: 生成大纲]
→ [LLM: 扩展每页内容为JSON]
→ [代码节点: 版式匹配]
→ [LLM: 生成配图Prompt]
→ [图像生成节点]
→ [HTTP节点: 调用渲染服务]
→ [输出PPTX]
```

### 2.2 结构化JSON Schema(关键)

```json
{
"theme": "business_blue",
"slides": [
{
"layout": "cover",
"title": "2024年度总结",
"subtitle": "业务增长与未来展望",
"background": "gradient_blue",
"decoration": "geometric"
},
{
"layout": "two_column_with_chart",
"title": "核心业绩",
"left": {
"type": "bullet_list",
"items": [
{"icon": "📈", "text": "营收增长 35%"},
{"icon": "👥", "text": "新增用户 200万"}
]
},
"right": {
"type": "chart",
"chart_type": "bar",
"data": {...}
}
},
{
"layout": "image_left_text_right",
"title": "产品升级",
"image_prompt": "modern dashboard UI",
"content": "..."
}
]
}
```

---

## 三、具体实现技术栈

### 方案A:HTML渲染路线(最美观) ⭐推荐

```python
# 1. 定义多套版式模板(HTML + Tailwind CSS)
templates = {
"cover": "cover.html",
"two_column_with_chart": "two_col.html",
"timeline": "timeline.html",
"comparison": "compare.html",
# ... 20+ 种版式
}

# 2. Jinja2渲染
from jinja2 import Environment
html = env.get_template(slide["layout"]).render(**slide)

# 3. 转换为PPT
# 方式1: HTML → 图片 → 嵌入PPT(保证完美还原)
from playwright.sync_api import sync_playwright
page.screenshot(path="slide1.png", full_page=True)

# 方式2: HTML → PDF → PPT
# 方式3: 直接返回HTML用Reveal.js在线展示
```

### 方案B:python-pptx + 预设模板

```python
# 使用预制.pptx模板,AI只填充占位符
from pptx import Presentation
prs = Presentation("templates/business_blue.pptx")

# 根据layout复制对应的母版页
slide_layout = prs.slide_layouts[layout_map[slide["layout"]]]
slide = prs.slides.add_slide(slide_layout)

# 填充占位符(PPT设计师预先在PPT里设计好样式)
for ph in slide.placeholders:
if ph.placeholder_format.idx == 0:
ph.text = slide["title"]
```

---

## 四、提升美观度的关键点

### 1. **预设主题系统**
```yaml
themes:
business_blue:
primary: "#1E40AF"
accent: "#3B82F6"
fonts: ["Inter", "思源黑体"]
decorations: ["geometric_lines"]
tech_dark:
primary: "#0F172A"
accent: "#06B6D4"
```

### 2. **版式库(至少准备15-20种)**
- 封面页、目录页、章节过渡页
- 单栏文字、双栏对比、三栏并列
- 图文左右、图文上下、大图铺满
- 数据图表、时间轴、流程图
- 引用页、结尾页

### 3. **智能配图**
- 调用 DALL-E 3 / SD / Flux 生成配图
- 或用 Unsplash API 搜索高质量图片
- 图标使用 Iconify / Lucide

### 4. **数据可视化**
- ECharts/Chart.js 生成图表截图嵌入
- 或用 python-pptx 原生图表

### 5. **AI版式决策**
```
Prompt: 根据以下内容,从版式库选择最合适的布局:
- 内容: {content}
- 要点数: {count}
- 是否有数据: {has_data}
- 可选版式: [cover, two_column, ...]
返回JSON: {"layout": "xxx", "reason": "..."}
```

---

## 五、完整架构图

```
用户输入主题

[工作流]
├─ Agent1: 生成整体大纲(控制逻辑与节奏)
├─ Agent2: 为每页生成结构化JSON(含版式选择)
├─ Agent3: 生成配图Prompt
├─ 并行: 文生图 + 图表数据生成
└─ 渲染服务
├─ HTML模板渲染(Jinja2 + Tailwind)
├─ Playwright截图 or 直接PPTX
└─ 输出 .pptx / .pdf / 在线链接
```

---

## 六、开源项目参考

| 项目 | 说明 |
|------|------|
| **[PPTAgent](https://github.com/icip-cas/PPTAgent)** | 清华开源,双阶段生成高质量PPT ⭐ |
| **VMind** | 字节开源,智能图表生成 |
| **Reveal.js** | HTML演示框架 |
| **Marp** | MD到PPT,支持主题 |
| **Slidev** | 开发者向HTML幻灯片 |
| **python-pptx** | Python操作PPT底层库 |

---

## 七、MVP落地建议(3周)

**Week 1**:
- 设计5-8套HTML版式模板
- 定义JSON Schema
- 搭建渲染服务(FastAPI + Playwright)

**Week 2**:
- 编排工作流节点(大纲→JSON→渲染)
- 调试Prompt,让AI稳定输出合法JSON
- 集成图像生成

**Week 3**:
- HTML转PPTX(推荐用截图嵌入方式,简单且还原度高)
- 主题系统、多风格适配
- 优化细节(字体、间距、动效)

---

需要我进一步提供某个部分的详细代码实现吗?比如:
1. HTML版式模板示例代码
2. AI生成JSON的Prompt工程
3. HTML→PPTX的转换实现
4. 完整工作流节点配置

 

 

# AI生成HTML样式 → 转换为PPT 完整实现方案

**完全可行**,这是目前最能保证美观度的方案之一。下面给你完整的技术实现路径。

---

## 一、核心技术路线

```
AI生成HTML(含CSS) → 浏览器渲染 → 截图/PDF → 嵌入PPTX

(每页一张高清图作为PPT底图)
```

### 为什么这样做?

| 方案 | 还原度 | 可编辑性 | 难度 |
|------|-------|---------|------|
| HTML → 图片嵌入PPT | ⭐⭐⭐⭐⭐ | ❌ 不可编辑 | 低 |
| HTML → SVG → PPT形状 | ⭐⭐⭐ | ⚠️ 部分 | 高 |
| HTML → 解析DOM → python-pptx元素 | ⭐⭐ | ✅ 可编辑 | 极高 |

**推荐:图片嵌入方案** —— 视觉100%还原,实现简单,客户基本不需要编辑AI生成的PPT。

---

## 二、完整实现代码

### 2.1 AI生成HTML的Prompt设计

```python
SYSTEM_PROMPT = """你是专业PPT设计师。请生成一个HTML页面作为PPT的一页幻灯片。

严格要求:
1. 页面尺寸必须是 1280x720px (16:9),使用固定尺寸
2. 使用内联CSS或<style>标签,不引用外部文件
3. 可以使用Tailwind CDN: https://cdn.tailwindcss.com
4. 可以使用Google Fonts
5. 图标使用 https://cdn.jsdelivr.net/npm/lucide-static/
6. 设计要求:现代、专业、有视觉层次
7. 使用渐变、阴影、几何装饰元素增强美感
8. 输出完整的HTML(含<!DOCTYPE html>)

版式类型: {layout_type}
内容: {content}
主题色: {theme_color}

只返回HTML代码,不要任何解释。"""
```

### 2.2 HTML → 图片(核心转换)

```python
# requirements: playwright, python-pptx, Pillow
# playwright install chromium

from playwright.sync_api import sync_playwright
from pptx import Presentation
from pptx.util import Inches, Emu
import os, tempfile

class HTMLToPPT:
WIDTH = 1280
HEIGHT = 720

def __init__(self):
self.tmp_dir = tempfile.mkdtemp()

def html_to_image(self, html_content: str, output_path: str):
"""将单页HTML渲染成高清PNG"""
with sync_playwright() as p:
browser = p.chromium.launch()
context = browser.new_context(
viewport={"width": self.WIDTH, "height": self.HEIGHT},
device_scale_factor=2 # 2倍分辨率,保证清晰
)
page = context.new_page()

# 直接加载HTML内容
page.set_content(html_content, wait_until="networkidle")

# 等待字体和图片加载
page.wait_for_timeout(1500)

page.screenshot(
path=output_path,
full_page=False,
clip={"x": 0, "y": 0, "width": self.WIDTH, "height": self.HEIGHT}
)
browser.close()

def build_pptx(self, html_list: list[str], output_pptx: str):
"""把多个HTML转成一个PPTX"""
prs = Presentation()
# 设置16:9尺寸
prs.slide_width = Inches(13.333)
prs.slide_height = Inches(7.5)

blank_layout = prs.slide_layouts[6] # 空白版式

for i, html in enumerate(html_list):
img_path = os.path.join(self.tmp_dir, f"slide_{i}.png")
self.html_to_image(html, img_path)

slide = prs.slides.add_slide(blank_layout)
slide.shapes.add_picture(
img_path, 0, 0,
width=prs.slide_width,
height=prs.slide_height
)

prs.save(output_pptx)
return output_pptx


# 使用示例
converter = HTMLToPPT()
html_pages = [html1, html2, html3] # AI生成的HTML列表
converter.build_pptx(html_pages, "output.pptx")
```

### 2.3 AI生成HTML示例(可直接用)

```python
import openai

def generate_slide_html(content: dict, theme: str = "blue") -> str:
prompt = f"""
生成一页PPT的HTML,要求:
- 尺寸: 1280x720px
- 主题: {theme}
- 内容: {content}
- 使用Tailwind CSS (CDN)
- 需要有装饰元素(几何形状/渐变)
- 文字要有层次感
只返回HTML。
"""
resp = openai.chat.completions.create(
model="gpt-4o",
messages=[
{"role": "system", "content": SYSTEM_PROMPT},
{"role": "user", "content": prompt}
]
)
return resp.choices[0].message.content
```

### 2.4 AI输出的HTML样例

```html
<!DOCTYPE html>
<html>
<head>
<script src="https://cdn.tailwindcss.com"></script>
<style>
body { margin:0; width:1280px; height:720px; overflow:hidden;
font-family:'Inter',sans-serif; }
.gradient-bg { background:linear-gradient(135deg,#1e3a8a 0%,#3b82f6 100%); }
.glass { backdrop-filter:blur(10px); background:rgba(255,255,255,0.1); }
</style>
</head>
<body class="gradient-bg relative">
<!-- 装饰圆 -->
<div class="absolute -top-40 -right-40 w-96 h-96 bg-blue-400 rounded-full opacity-20 blur-3xl"></div>
<div class="absolute -bottom-20 -left-20 w-80 h-80 bg-cyan-300 rounded-full opacity-20 blur-3xl"></div>

<!-- 主内容 -->
<div class="relative z-10 h-full flex flex-col justify-center px-24">
<div class="text-cyan-300 text-sm tracking-[0.3em] mb-6">2024 ANNUAL REPORT</div>
<h1 class="text-white text-7xl font-bold mb-6 leading-tight">
业务增长<br/>与未来展望
</h1>
<div class="w-24 h-1 bg-cyan-400 mb-8"></div>
<p class="text-blue-100 text-xl max-w-xl">
聚焦核心业务,驱动创新发展
</p>
</div>

<!-- 底部信息 -->
<div class="absolute bottom-12 right-24 glass rounded-lg px-6 py-3 text-white">
<div class="text-xs opacity-70">PRESENTED BY</div>
<div class="text-lg font-semibold">AI Studio</div>
</div>
</body>
</html>
```

---

## 三、在工作流平台的节点编排

```
┌─────────────────────────────────────────────────────┐
│ 节点1: [LLM] 生成PPT大纲 │
│ 输入: 用户主题 │
│ 输出: slides数组 [{title,type,content},...] │
├─────────────────────────────────────────────────────┤
│ 节点2: [迭代/循环] 对每一页 │
│ └─ [LLM] 生成该页HTML │
│ Prompt含: 版式类型、内容、主题色 │
├─────────────────────────────────────────────────────┤
│ 节点3: [HTTP] 调用转换服务 │
│ POST /convert { html_list: [...] } │
│ 返回: PPT文件URL │
├─────────────────────────────────────────────────────┤
│ 节点4: [输出] 返回下载链接 │
└─────────────────────────────────────────────────────┘
```

### FastAPI 渲染服务

```python
from fastapi import FastAPI
from fastapi.responses import FileResponse
from pydantic import BaseModel

app = FastAPI()

class ConvertRequest(BaseModel):
html_list: list[str]
filename: str = "presentation.pptx"

@app.post("/convert")
def convert(req: ConvertRequest):
converter = HTMLToPPT()
output = f"/tmp/{req.filename}"
converter.build_pptx(req.html_list, output)
return FileResponse(output, filename=req.filename)
```

---

## 四、关键优化点

### 1. **并发渲染**(速度提升5-10倍)

```python
import asyncio
from playwright.async_api import async_playwright

async def render_all(html_list):
async with async_playwright() as p:
browser = await p.chromium.launch()
tasks = [render_one(browser, html, i) for i, html in enumerate(html_list)]
return await asyncio.gather(*tasks)
```

### 2. **让AI输出稳定**

- 提供HTML模板骨架,AI只填内容区域
- 用JSON Schema约束输出
- 限制AI可用的CSS类(白名单)

```python
# 混合模式:AI只生成内容区,外层骨架固定
SKELETON = """
<!DOCTYPE html>
<html><head>...固定样式...</head>
<body>
<div class="slide-container">
{{AI_CONTENT}} <!-- 只让AI生成这部分 -->
</div>
</body></html>
"""
```

### 3. **资源预加载**

```python
# 把常用字体、图标提前本地化,避免外网延迟
page.route("**/*.{png,jpg,woff2}", lambda r: r.continue_())
```

### 4. **版式模板库(强烈推荐)**

与其让AI完全自由生成,不如准备 **15-20套精美HTML模板**,AI只负责:
- 选择模板
- 填充内容
- 微调主题色

这样能保证**每一页都是设计师级别**的质量。

---

## 五、踩坑提醒

| 问题 | 解决方案 |
|------|---------|
| 中文字体显示不全 | Docker镜像安装 `fonts-noto-cjk` |
| Tailwind CDN加载慢 | 本地化或用JIT预编译 |
| 生成的PPT文件大 | 图片压缩至 85% JPEG,或 WebP |
| AI输出HTML有错误 | 加一层HTML验证 + 自动修复Prompt |
| 动画效果丢失 | 截图是静态的,可用GIF或改交付HTML |

---

## 六、进阶:保留可编辑性

如果客户需要**可编辑**的PPT,可以用混合方案:

```python
# 背景用HTML截图,文字用python-pptx添加文本框
slide.shapes.add_picture(bg_image, 0, 0, ...) # 装饰背景
txt_box = slide.shapes.add_textbox(...) # 可编辑标题
txt_box.text_frame.text = "标题"
```

---

## 七、推荐部署方案

```yaml
# docker-compose.yml
services:
html2ppt:
image: mcr.microsoft.com/playwright/python:latest
ports: ["8000:8000"]
volumes:
- ./app:/app
command: uvicorn main:app --host 0.0.0.0
```

---

## 总结

✅ **完全可行**,且这是当前能达到**最高美观度**的方案
✅ 核心技术栈:**Playwright + python-pptx**
✅ 关键是**Prompt工程** + **预设模板**
✅ 单页渲染约 1-2 秒,并发后 10 页 PPT 约 3-5 秒

需要我提供以下哪个的完整代码?
1. 📦 **完整的Docker化服务**(开箱即用)
2. 🎨 **10套精美HTML版式模板**
3. 🤖 **AI生成HTML的Prompt全集**
4. 🔀 **工作流节点的完整配置JSON**

 
 
 
# 通用 PPT 生成提示词集合

我基于这两种风格,提炼并扩展了以下几个通用模板,覆盖不同使用场景:

---

## 🔷 风格一:中国企业科技蓝商务风(强化通用版)

```
# 角色
你是资深 PPT 设计师 + 前端工程师,精通 pptxgenjs 库,擅长「中国企业科技蓝」商务风幻灯片。

# 任务
生成单个 .html 文件,主题为「{{主题}}」,共 {{N}} 页。
该文件在浏览器中是交互式 PPT 预览器,点击右上角「📥 导出 PPTX」按钮,
可通过 pptxgenjs 生成视觉上与 HTML 完全一致的 .pptx 文件。

# 一、整体架构
1. 单文件 HTML,内联 CSS + JS,零本地依赖;
   导出时动态从 CDN 加载 https://unpkg.com/pptxgenjs@4.0.1/dist/pptxgen.bundle.js
   并带 loadScript + ensurePptxGen 失败重试机制。
2. 页面结构:
   - 顶部控制栏(.control-bar,高54px,白底):
     左侧 logo 圆角图标(品牌蓝背景)+ 品牌名 + 胶囊状页码计数器「1 / N」;
     右侧「◀上一页 / 下一页▶ / 📥导出 PPTX」三按钮。
   - 进度条(.progress):顶栏下方 3px 蓝色横条,宽度随页码变化,0.4s 缓动。
   - 舞台区(.stage):max-width:1000px,aspect-ratio:16/9,
     白底圆角12px + 柔和阴影;切换带 translateX + scale + opacity 缓动。
   - 底部 dots 栏(.dots-bar,高60px):圆点导航,当前页胶囊化(宽28px,蓝色)。
   - Toast 通知(.toast):info/success/error 三色,右上角弹出(导出过程反馈)。
3. 交互:← → 方向键翻页、触摸滑动、点击圆点跳转。
4. 关键字体:'Microsoft YaHei', '微软雅黑', sans-serif。

# 二、视觉设计系统(科技蓝商务风)
主色板(HTML 与 PPTX 必须同色号):
  主蓝 #1a6bff     深蓝 #1558d6      浅蓝 #edf2ff      浅蓝底 #e8f0ff
  深文字 #1a1a1a   次文字 #888888    浅灰底 #f7f9fc    边框 #e8ecf2
  强调红 #e03030   强调绿 #0a8040    强调橙 #e06800    警告黄底 #fffbec / 边 #f0d060

字号规范:封面主标 38-42px、章节标题 22-24px、卡片标题 12-14px、
          正文 10.5-12px、标签 9-10px(letter-spacing:2-2.5px, uppercase)

统一元素:
  - 每章节页顶部 4px 蓝色装饰横条
  - 章节小标签「0X · ENGLISH」(蓝色、粗体、字距2.5px、大写)
  - 标题可混排蓝色强调词
  - 卡片:浅灰底 #f7f9fc + 1px 边框 #e8ecf2 + 圆角 8-12px
  - 图标容器:彩色柔和底(#e8f0ff / #fff2e8 / #eafaf0)+ emoji 图标
  - 标签小胶囊:浅蓝底 + 蓝字 + 粗体

# 三、推荐页面模板(按主题组合)
1. 封面页:左右分栏,左侧大面积蓝色背景 + 装饰圆 + 胶囊 badge + 巨型标题 + 英文副标;
           右侧白色 + 5 个彩色图标标签项列表。
2. 目录页:左侧 220px 蓝色竖栏(CONTENTS + 大字)+ 右侧 N 行卡片列表。
3. 概念定义页:左 def-box(浅蓝底定义框)+ 要点列表;右侧纵向流程卡片。
4. 矩阵/工具页:3×22×3 卡片网格,每卡含图标 + 标题 + 描述 + 标签。
5. 对比页(VS):左红色表头 + 右蓝色表头,中间竖线 + VS 徽章。
6. 代码/树形页:深色代码框 #1a1a2a + 彩色 Courier New;右侧说明卡片。
7. 总结/路线图页:顶部蓝色横幅 + 4 个阶段卡片 + 底部黄色警示条。

# 四、PPTX 导出(与 HTML 1:1 还原)
const pptx = new PptxGenJS();
pptx.layout = 'LAYOUT_WIDE';  // 13.33 × 7.5 英寸 16:9
const W = 13.33, H = 7.5;
const C = {
  blue:'1a6bff', darkBlue:'1558d6', white:'FFFFFF', dark:'1a1a1a',
  gray:'888888', light:'f7f9fc', border:'e8ecf2', lightBlue:'edf2ff',
  red:'e03030', green:'0a8040', orange:'e06800'
};

辅助函数:
  addWhiteBg(s)  → 白底矩形铺满
  addTopBar(s)   → 顶部 4px 蓝色装饰条
  sLabel(s, txt) → 章节小标签(蓝色、字距2.5px)
  sTitle(s, parts) → 混色标题数组

每页必备:白底 + 顶部蓝条 + 章节标签 + 混色标题
卡片:addShape(roundRect) + addText 叠加
图标容器:彩色小圆角矩形 + emoji 居中
装饰圆:addShape(ellipse) 置于角落

布局基准(英寸):
  左右留白 0.36-0.42";内容主区 y=1.26" 起;标题在 y=0.22-0.52"
  3×2 卡片:cw=4.15, ch=2.42, gx=0.19, gy=0.14
  2×3 卡片:cw=6.3,  ch=1.7,  gx=0.25, gy=0.15

# 五、内容要求
- {{N}} 页合理大纲:封面 → 目录 → 概念 → 工具/要素 → 结构/分类 → 方法/技术 → 对比 → 总结
- 中文为主,英文仅用于标签、代码、术语;信息密度适中
- 所有图示用原生形状 + 文字绘制,不引入图片资源

# 六、交付
直接输出完整 .html 文件代码(单一代码块),确保:
- 浏览器打开可流畅预览、键盘/触摸可翻页
- 点击「📥 导出 PPTX」→ Toast 提示「生成中」→ 成功下载 {{主题}}.pptx
- PPTX 每页色彩、布局、文字、图标与 HTML 版本视觉一致

---
主题 = "{{在此填写}}"
N = {{页数}}
```

---

## 🍎 风格二:Apple 极简黑白风(强化通用版)

```
# 角色
你是资深 PPT 设计师 + 前端工程师,擅长 Apple 风格极简设计和 pptxgenjs 库。

# 任务
生成单个 .html 文件,主题是「{{主题}}」,共 {{N}} 页幻灯片。
该 HTML 在浏览器中是交互式 PPT 预览器,带一键「导出 PPTX」按钮,
点击后通过 pptxgenjs 生成视觉上与 HTML 完全一致的 .pptx 文件。

# 一、整体架构
1. 单个 .html 文件,内联 CSS + JS,零外部依赖;
   pptxgenjs 在点击导出时动态加载:https://unpkg.com/pptxgenjs@4.0.1/dist/pptxgen.bundle.js
2. 页面布局三区:
   - 顶部固定栏(高52px,毛玻璃 backdrop-filter:blur(20px)):
     左侧 app 图标 + 标题,中间「← 页码 →」导航,右侧黑色「↓ 导出 PPTX」按钮
   - 左侧缩略图栏(宽180px,毛玻璃):
     由 JS 根据 slidesData 数组动态生成,含页码、标题、副标题,点击跳转,当前页高亮
   - 主内容区:单张 .slide 容器,aspect-ratio:16/9,max-width:960px,
     白底、圆角16px、柔和阴影;通过 .active 类切换,带 slideIn 淡入动画
3. 交互:左右方向键翻页、点击缩略图跳转、点击进度点跳转
4. 导出时显示「正在生成 PPTX 文件」loading 遮罩层

# 二、视觉设计系统(Apple 极简风)
调色板(HTML 与 PPTX 必须同色):
  黑 #1d1d1f | 灰 #6e6e73 | 浅灰背景 #f5f5f7 | 边框 #d2d2d7 | 白 #ffffff
  强调蓝 #0071e3 | 深强调 #0077ed | 浅蓝底 #e8f0fe

字体:-apple-system, BlinkMacSystemFont, 'SF Pro Display', 'Helvetica Neue', Arial
      PPTX 中用 Arial;代码用 Courier New

字号规范:主标题 46-52px、章节标题 28px、卡片标题 12-14px、正文 10-12px、页脚 8-9px

元素规范:
  - 每页左边缘 0.06" 宽纯黑装饰竖条
  - 章节标签「CHAPTER 0X」大写 + 字距 1px + 下方 40px 黑色 accent-line
  - 卡片:border-radius 12-16px + 浅灰背景 #f5f5f7 + 1px 细边框
  - 首页可用毛玻璃 .glass-card 作右侧视觉元素
  - 页脚:左品牌字 + 中间细线 + 右「0X / XX」页码

# 三、HTML 结构关键类名
.top-bar / .sidebar .thumb-item / .slide-wrapper > .slide.slide-N
每张 .slide 内:
  .slide-content >
    .section-header(.section-label + .accent-line + .section-title)+
    主体区 +
    .slide-footer

布局模式可选:
  首页左右分栏 | two-col 双列卡片 | tool-list 列表 |
  5步时间线(圆圈+连接线)| 三/四列卡片网格 | 数据统计大数字

JS 维护 slidesData = [{num, title, subtitle}, ...] 用于生成缩略图

# 四、PPTX 导出(逐页 1:1 还原)
const pptx = new PptxGenJS();
pptx.layout = 'LAYOUT_WIDE';  // 13.33 × 7.5 英寸 16:9
const C = {
  black:'1d1d1f', gray:'6e6e73', lightGray:'f5f5f7',
  border:'d2d2d7', white:'ffffff', blue:'0071e3'
};

每页构建顺序(独立 {} 块):
  1. slide.background = { color: C.white }
  2. 左边缘黑色装饰竖条(x:0, y:0, w:0.06, h:7.53. CHAPTER 0X 标签 + 装饰短横线 + 章节大标题
  4. 卡片:addShape(roundRect, {rectRadius:0.12, fill:{color:C.lightGray},
           line:{color:'e8e8ed', width:1}}) + addText 叠加
  5. 强调块:反色(黑底白字)
  6. 图标:Emoji 直接写入文字
  7. 页脚:品牌字(x:0.5)+ 页码(x:11.5)两端对齐

坐标基准(英寸):
  页面 13.33" × 7.5";左右留白 0.5";内容宽 12.3"
  左右两栏:每栏 5.8",间距 0.4"
  章节标题 y=0.95;主体区 y=1.85 起;页脚 y=7.0

# 五、内容要求
- {{N}} 页大纲自行设计,需含封面页 + 章节页 + 总结/路线图页
- 中文为主,数据/代码/术语用英文,信息密度适中不堆砌
- 所有可视化元素用原生形状 + 文字绘制,不引入图片

# 六、交付
直接输出完整 .html 文件代码(一个代码块,无多余解释),确保:
- 浏览器打开即可预览、键盘可翻页
- 点击「导出 PPTX」成功下载 {{主题}}.pptx,打开后每页与 HTML 视觉一致

---
主题 = "{{在此填写}}"
N = {{页数}}
```

---

## 🌙 风格三:暗黑科技风(深色主题)【新增】

```
# 角色
你是资深 PPT 设计师 + 前端工程师,精通 pptxgenjs,擅长「深色科技赛博朋克」风幻灯片。

# 任务
生成单个 .html 文件,主题为「{{主题}}」,共 {{N}} 页。
浏览器中为交互式预览器,点击「⚡ 导出 PPTX」通过 pptxgenjs 生成与 HTML 视觉一致的 .pptx 文件。

# 一、整体架构
1. 单文件 HTML,内联 CSS + JS,零本地依赖;
   导出时动态加载 https://unpkg.com/pptxgenjs@4.0.1/dist/pptxgen.bundle.js
2. 页面结构(全局深色背景 #0a0a0f):
   - 顶部控制栏(高56px,半透明深色 rgba(10,10,20,0.9),backdrop-filter:blur(20px),
     底部 1px 渐变边框 linear-gradient(90deg,#00d4ff,#7b2fff)):
     左侧霓虹 logo(渐变文字 #00d4ff→#7b2fff)+ 品牌名;
     右侧页码 + 「◀ ▶」导航 + 「⚡ 导出 PPTX」渐变按钮
   - 进度条(2px 渐变横条 #00d4ff→#7b2fff)
   - 舞台区:max-width:1040px,aspect-ratio:16/9,深色背景 #0d0d1a,
     圆角14px;边框 1px solid rgba(0,212,255,0.15);
     box-shadow: 0 0 40px rgba(0,212,255,0.08);切换带缓动动画
   - 底部 dots:当前页为渐变胶囊(#00d4ff→#7b2fff)
   - Toast:赛博风(深色背景 + 霓虹色边框)

3. 交互:← → 方向键翻页、触摸滑动、圆点跳转
4. 字体:'JetBrains Mono', 'Fira Code', 'Microsoft YaHei', monospace(营造科技感)

# 二、视觉设计系统(深色赛博风)
调色板(HTML 与 PPTX 必须同色号):
  深底   #0a0a0f   #0d0d1a   #12121f   #1a1a2e
  卡片底 #16162a   卡片边 rgba(0,212,255,0.12)
  青蓝   #00d4ff   紫蓝  #7b2fff   绿色  #00ff88
  警告橙 #ff6b35   错误红 #ff2d55   文字白 #e8e8f0   次文字 #8888aa

渐变系统:
  主渐变 linear-gradient(135deg, #00d4ff, #7b2fff)
  绿渐变 linear-gradient(135deg, #00ff88, #00d4ff)
  暖渐变 linear-gradient(135deg, #ff6b35, #ff2d55)

字号规范:封面主标 40-48px、章节标题 24-28px、卡片标题 13-15px、正文 11-12px

统一元素:
  - 每页左侧 3px 渐变装饰竖条(青→紫)
  - 章节标签:大写英文 + 字距 3px + 青色 #00d4ff + 发光效果 text-shadow:0 0 10px #00d4ff
  - 卡片:深色底 #16162a + 渐变边框(用伪元素或 border-image)+ 圆角 10-14px
  - 数据大字:渐变色填充 + 发光阴影
  - 代码块:更深底色 #080810 + 彩色语法高亮
  - 图标:渐变色圆形容器 + emoji

# 三、推荐页面模板
1. 封面页:全屏深色 + 动态粒子背景(CSS 动画模拟)+ 居中超大渐变标题
           + 科技感英文副标 + 右下角数据统计卡
2. 目录页:左侧渐变竖栏 + 右侧 N 个霓虹卡片(编号 + 标题 + 一句话描述)
3. 概念页:左侧青色发光定义框 + 右侧流程步骤(竖向,节点用渐变圆)
4. 矩阵页:3×2 深色卡片网格,顶部渐变色条区分类别
5. 对比页:黑底白线分割 + 左红霓虹 vs 右青霓虹
6. 数据页:4 个超大数字卡(渐变色数字 + 灰色描述)
7. 代码页:全宽深色代码编辑器风格 + 行号 + 语法高亮 + 右侧注解卡
8. 时间线页:横向时间轴,节点为渐变圆,连接线为虚线
9. 总结页:网格背景 + 居中渐变大字 + 底部 3 条金句卡片

# 四、PPTX 导出
const pptx = new PptxGenJS();
pptx.layout = 'LAYOUT_WIDE';
const W = 13.33, H = 7.5;
const C = {
  bg:     '0d0d1a', card:  '16162a', dark:  '0a0a0f',
  cyan:   '00d4ff', purple:'7b2fff', green: '00ff88',
  orange: 'ff6b35', red:   'ff2d55', white: 'e8e8f0',
  gray:   '8888aa', border:'1e1e3a'
};

注意:PPTX 中渐变用 fill:{type:'solid'} 近似处理,优先用青色 #00d4ff 作主色;
深色背景用实色矩形铺满;发光效果省略(PPTX 不支持)

每页必备:深色背景矩形 + 左侧渐变竖条(近似用青色)+ 章节标签 + 标题

布局基准同科技蓝版本,色值替换为深色系

# 五、内容要求
- {{N}} 页大纲:封面 → 目录 → 核心概念 → 技术矩阵 → 数据洞察 → 对比分析 → 代码示例 → 总结
- 数据、代码、英文术语优先展示,中文解释辅助
- 强调视觉冲击力,可适当使用警告/状态类信息

# 六、交付
直接输出完整 .html 文件代码(单一代码块),确保:
- 深色主题全局生效,浏览器预览视觉震撼
- 键盘/触摸翻页流畅,动画缓动自然
- 导出 PPTX 中深色背景完整还原

---
主题 = "{{在此填写}}"
N = {{页数}}
```

---

## 📊 风格四:数据报告/商业分析风(Data Dashboard)【新增】

```
# 角色
你是资深数据可视化设计师 + 前端工程师,擅长 Dashboard 风格商业报告 PPT 和 pptxgenjs。

# 任务
生成单个 .html 文件,主题为「{{主题}}」,共 {{N}} 页数据报告幻灯片。
浏览器中为交互式预览器,点击「📊 导出 PPTX」生成与 HTML 视觉一致的 .pptx 文件。

# 一、整体架构
1. 单文件 HTML,内联 CSS + JS,零本地依赖;
   导出时动态加载 https://unpkg.com/pptxgenjs@4.0.1/dist/pptxgen.bundle.js
2. 页面结构(整体风格:深蓝灰底 + 白卡浮层):
   - 顶部导航栏(高60px,深色 #1e2235,右侧「📊 导出」白色圆角按钮)
   - 主舞台:aspect-ratio:16/9,max-width:1040px,
     背景 #1e2235(深蓝灰),圆角12px
   - 每张幻灯片内:左侧固定侧边信息条(宽200px,更深 #161929)+
     右侧主内容区(白色/浅色卡片网格)
   - 底部控制条:页码圆点 + 左右箭头

3. 字体:'Inter', 'DIN', 'Helvetica Neue', 'Microsoft YaHei', sans-serif

# 二、视觉设计系统(数据 Dashboard 风)
调色板:
  深底   #1e2235   侧边栏 #161929   卡片白 #ffffff   卡片灰 #f4f5f8
  主蓝   #4e85fd   次蓝   #6c9fff   青绿   #00c9a7   警橙   #ff8c42
  品红   #e040fb   数字强调 #ffffff   描述灰 #8892b0   标题白 #ccd6f6

图表模拟元素(原生形状绘制):
  - 柱状图:多个等宽矩形,高度按数据比例,底部对齐,不同蓝色系填充
  - 折线图:多个小圆点 + 连接线段(addLine)
  - 环形图:用扇形 addShape(pie) 近似 或多个弧形矩形叠加
  - 进度条:底色矩形 + 前景色矩形(圆角)
  - 数据卡:大号白色数字 + 小字描述 + 趋势箭头(↑↓)+ 彩色左边框

统一元素:
  - KPI 大数字卡:深色底 + 彩色数字(48-56px)+ 单位 + 环比变化
  - 表格:深色表头 + 隔行深浅交替(#1e2235 / #242840)+ 彩色状态标签
  - 图例:小圆点 + 说明文字,横排
  - 左侧边栏:报告名称(竖排或横排)+ 数据来源 + 报告期 + 分割线

# 三、推荐页面模板
1. 封面页:深色全屏 + 居中大标题(白色)+ 副标题 + 数据来源 + 报告日期
           + 右上角 logo 区域 + 左下角彩色装饰条
2. 执行摘要页:左侧边栏 + 右侧 3-4 个 KPI 大数字卡并排
3. 趋势分析页:左侧边栏 + 右侧折线图(原生形状模拟)+ 数据标注
4. 结构占比页:左侧边栏 + 右侧环形图(原生近似)+ 图例说明
5. 排行榜页:左侧边栏 + 右侧水平条形图(按数据长度的矩形)+ 数值标签
6. 对比分析页:左侧边栏 + 右侧两列柱状图并排(不同颜色系)
7. 数据表格页:左侧边栏 + 右侧深色风格数据表(5-8 行)
8. 关键洞察页:左侧边栏 + 右侧 3-4 个洞察卡片(左彩色竖条 + 标题 + 描述)
9. 预测/规划页:左侧边栏 + 右侧时间轴/甘特图(原生矩形模拟)
10. 总结建议页:深色全屏 + 3 条建议卡(图标 + 标题 + 描述)+ 底部说明

# 四、PPTX 导出
const pptx = new PptxGenJS();
pptx.layout = 'LAYOUT_WIDE';
const W = 13.33, H = 7.5;
const C = {
  bg:    '1e2235', sidebar: '161929', white: 'ffffff',
  card:  'f4f5f8', blue:    '4e85fd', cyan:  '00c9a7',
  orange:'ff8c42', purple:  'e040fb', gray:  '8892b0',
  text:  'ccd6f6', dark:    '242840'
};

图表还原规范:
  柱状图:每根柱子 addShape(rect),x/w 均匀分布,h 按数据比例,y 从底部上移
  进度条:addShape(rect,{fill:{color:C.dark}}) 底 + addShape(rect,{fill:{color:C.blue}}) 前景
  趋势箭头:addText('↑ +12.3%', {color:'00c9a7'}) 绿色上升 / 红色下降
  数据标签:addText 在对应形状正上方或内部

侧边栏(每页):
  addShape(rect, {x:0, y:0, w:2.8, h:7.5, fill:{color:C.sidebar}})
  + 报告名(竖向文字或横向)+ 分割线 + 期数/来源

# 五、内容要求
- 根据「{{主题}}」自动设计合理的数据报告大纲({{N}} 页)
- 所有数据为示例性模拟数据,标注「示意数据,仅供参考」
- 数据单位、同比/环比、时间周期等信息完整
- 图表类型多样,至少包含:KPI卡、折线/柱状、占比、表格、洞察卡

# 六、交付
直接输出完整 .html 文件代码(单一代码块),确保:
- 深色 Dashboard 风格完整呈现
- 原生形状图表在 HTML 和 PPTX 中均正确渲染
- 导出 PPTX 文件名为「{{主题}}_报告.pptx」

---
主题 = "{{在此填写,如:2024年Q3销售分析报告}}"
N = {{页数,建议10-12}}
```

---

## 🎓 风格五:教育培训风(课程讲义风)【新增】

```
# 角色
你是资深教学设计师 + 前端工程师,擅长制作清晰易读的课程培训 PPT 和 pptxgenjs 导出。

# 任务
生成单个 .html 文件,课程主题「{{主题}}」,共 {{N}} 页。
浏览器中为交互式课件预览器,支持「🖨 导出 PPTX」一键导出课件文件。

# 一、整体架构
1. 单文件 HTML,内联 CSS + JS,零外部依赖;
   导出时动态加载 https://unpkg.com/pptxgenjs@4.0.1/dist/pptxgen.bundle.js
2. 页面结构(风格:暖白 + 橙绿强调,适合学习场景):
   - 顶部课件栏(高58px,白色,底部 3px 橙色横线):
     左侧课程图标 + 课程名称;
     中间章节面包屑导航;
     右侧进度「第 N/M 页」+ 导出按钮
   - 主舞台:aspect-ratio:16/9,max-width:1000px,白底,圆角10px,阴影
   - 底部学习进度条(橙色填充,百分比)+ 翻页按钮

3. 字体:'Noto Sans SC', 'PingFang SC', 'Microsoft YaHei', sans-serif
4. 交互:← → 翻页、Space 下一页、数字键跳转

# 二、视觉设计系统(教育培训风)
调色板:
  白底   #ffffff   浅暖灰 #fafaf8   卡片底 #f7f6f3
  橙主   #f97316   浅橙底 #fff7ed   深橙   #ea6c00
  绿主   #22c55e   浅绿底 #f0fdf4   蓝主   #3b82f6   浅蓝底 #eff6ff
  紫主   #8b5cf6   浅紫底 #f5f3ff   红主   #ef4444   浅红底 #fef2f2
  深文字 #1c1917   次文字 #78716c   边框   #e7e5e4

教学专用元素:
  - 知识点卡片:带左侧 4px 彩色竖条(不同知识点不同颜色)+ 浅色背景
  - 重点标注:🔑 图标 + 橙色粗体 + 浅橙底色框
  - 注意事项:⚠️ 图标 + 黄色警示框(边框 + 浅黄底)
  - 记忆口诀:引号样式框 + 斜体大字 + 橙色引号符
  - 步骤流程:带序号圆圈(橙色填充白数字)+ 步骤描述 + 箭头连接
  - 练习题卡:浅蓝底 + 🧩 图标 + 题目 + 答案折叠(HTML 可点击展开)
  - 小结卡:绿色对勾列表,3-5 条核心要点
  - 难度标签:⭐⭐⭐ + 「初级/中级/高级」胶囊
  - 知识关联图:箭头连接多个概念节点(原生形状)

字号规范:课程标题 36-40px、章节标题 22-26px、正文 13-15px(比商务 PPT 大)、注释 11px

# 三、推荐页面模板
1. 封面页:居中布局 + 课程大标题 + 适合人群/难度/时长三标签 + 知识点预告
2. 学习目标页:左侧大「🎯」图标 + 右侧 4-5 条「学完本课你将会...」列表
3. 概念导入页:生活类比引入 → 正式定义框 → 3 个核心特点卡片
4. 详解页:左侧知识点卡片列表 + 右侧图示(原生形状绘制的示意图)
5. 对比辨析页:两列对比表,含相同点/不同点,绿色✓ / 红色✗
6. 步骤操作页:横向或纵向步骤流(4-6步,带序号圆圈)
7. 案例分析页:左侧案例背景 + 右侧分析要点 + 底部结论框
8. 练习巩固页:2-3 道练习题(选择/判断),HTML 可点击显示答案
9. 知识图谱页:中心概念 + 放射形关联节点(原生形状+连线)
10. 课程小结页:绿色对勾要点 + 下一课预告 + 推荐资源列表

# 四、PPTX 导出
const pptx = new PptxGenJS();
pptx.layout = 'LAYOUT_WIDE';
const W = 13.33, H = 7.5;
const C = {
  white: 'ffffff', warm:  'fafaf8', card:  'f7f6f3',
  orange:'f97316', lightO:'fff7ed', green: '22c55e', lightG:'f0fdf4',
  blue:  '3b82f6', lightB:'eff6ff', purple:'8b5cf6', lightP:'f5f3ff',
  dark:  '1c1917', gray:  '78716c', border:'e7e5e4'
};

教学元素还原:
  知识点卡片:addShape(rect,{fill:{color:C.lightO}}) + 左边 addShape(rect,{w:0.05,fill:{color:C.orange}})
  步骤圆圈:addShape(ellipse,{fill:{color:C.orange}}) + addText('1',{color:C.white,bold:true})
  重点框:addShape(roundRect,{fill:{color:C.lightO},line:{color:C.orange}})
  箭头连接:addShape(rect,{h:0.03,fill:{color:C.border}}) 模拟连接线

# 五、内容要求
- 根据「{{主题}}」设计 {{N}} 页完整课程,循序渐进(入门→理解→应用→总结)
- 每页信息量适中(不超过5个知识点),留有呼吸空间
- 多用类比、举例、对比帮助理解,少用纯文字堆砌
- 包含至少 1 页练习题(HTML 中可展开答案)
- 标注难度等级和预计学习时长

# 六、交付
直接输出完整 .html 文件代码(单一代码块),确保:
- 暖色教育风格完整呈现,适合学习阅读
- 练习题答案可折叠交互正常
- 导出 PPTX 文件名「{{主题}}_课件.pptx」

---
主题 = "{{在此填写,如:Python 基础入门第一课}}"
N = {{页数,建议12-15}}
```

---

## 🌿 风格六:简约自然风(绿色环保/品牌故事风)【新增】

```
# 角色
你是品牌视觉设计师 + 前端工程师,擅长自然简约风格 PPT 和 pptxgenjs 导出。

# 任务
生成单个 .html 文件,主题「{{主题}}」,共 {{N}} 页品牌/故事型幻灯片。
浏览器中为交互式预览器,支持「🌿 导出 PPTX」一键导出。

# 一、整体架构
1. 单文件 HTML,内联 CSS + JS,零本地依赖;
   导出时动态加载 https://unpkg.com/pptxgenjs@4.0.1/dist/pptxgen.bundle.js
2. 页面结构(整体基调:米白底色 + 绿色系强调 + 有机圆形元素):
   - 顶部导航(高52px,米白 #faf9f6,底部 1px 边框 #e8e4dd):
     左侧叶片形 logo + 品牌名(深绿色);右侧页码 + 导出按钮(深绿色填充)
   - 主舞台:aspect-ratio:16/9,max-width:1000px,
     背景 #faf9f6(米白),圆角16px,暖色阴影
   - 底部翻页控制:细线分割 + 圆点导航(绿色当前页)

3. 字体:'Georgia', 'Noto Serif SC', 'Microsoft YaHei', serif(衬线字体增加温度感)
4. 装饰风格:有机圆形(椭圆),不规则色块,留白充足,文字排版精良

# 二、视觉设计系统(自然简约风)
调色板:
  米白底  #faf9f6   暖灰   #f0ede6   卡片   #ffffff
  深绿    #2d5a27   中绿   #4a7c59   浅绿底 #eef4eb
  棕色    #8b6914   浅棕底 #fdf5e6   赤褐   #a0522d
  石蓝    #4a6fa5   浅蓝底 #edf2f7
  深文字  #2c2c2c   次文字 #6b6b6b   浅文字 #9a9a9a   边框  #ddd8d0

有机设计元素:
  - 大圆形装饰块(半透明浅绿/浅棕,作为背景装饰)
  - 细线分割(1px,#ddd8d0,非粗线条)
  - 引用块(左侧 3px 深绿竖条 + 浅绿底 + 衬线斜体文字)
  - 数字用大号衬线字体,彩色
  - 标签:圆角胶囊,绿色边框 + 绿色文字(描边风格,无填充)
  - 图标用 emoji,无需彩色背景(直接大号展示)

字号规范(比商务 PPT 更宽松):
  封面主标 42-48px(衬线)、副标 16-18px(无衬线,灰色)
  章节标题 24-28px、正文 13-14px、引用 15-16px(斜体)、标注 11px

# 三、推荐页面模板
1. 封面页:大面积留白 + 居中标题(衬线大字)+ 右下角圆形装饰色块
           + 底部细线 + 副标题 + 品牌标语
2. 使命/愿景页:左侧大圆形色块装饰 + 右侧超大引用字体
3. 核心价值页:3 列价值观卡片(大号 emoji + 标题 + 2-3 行描述,大量留白)
4. 故事/历程页:横向时间轴,节点为有机圆点,下方文字说明(简洁)
5. 数据展示页:3-4 个大号数字卡(衬线字体 + 彩色 + 单位 + 简短描述)
6. 产品/服务页:2 列或 3 列,每格含图示(原生形状)+ 标题 + 描述
7. 团队/人物页:4 个圆形头像框(用首字母代替)+ 姓名 + 职位 + 一句话
8. 认证/合作页:logo 网格(用文字+边框矩形代替)+ 资质描述
9. 用户故事页:卡片引用风格(引号 + 用户说的话 + 来源标注)
10. 行动召唤页:全屏深绿背景 + 白色大字 + 联系方式 + 二维码(方块模拟)

# 四、PPTX 导出
const pptx = new PptxGenJS();
pptx.layout = 'LAYOUT_WIDE';
const W = 13.33, H = 7.5;
const C = {
  bg:      'faf9f6', warm:  'f0ede6', white: 'ffffff',
  dGreen: '2d5a27',  mGreen:'4a7c59', lGreen:'eef4eb',
  brown:  '8b6914',  lBrown:'fdf5e6', stone: '4a6fa5',
  dark:   '2c2c2c',  gray:  '6b6b6b', lgray: '9a9a9a',
  border: 'ddd8d0'
};

有机元素还原:
  装饰大圆:addShape(ellipse,{fill:{color:C.lGreen},line:{type:'none'}}) 置于角落
  引用块:addShape(rect,{x,y,w:0.04,h,fill:{color:C.dGreen}}) 绿色左边条
          + addShape(rect,{fill:{color:C.lGreen}}) 浅绿底
  细分割线:addShape(rect,{h:0.01,fill:{color:C.border}})
  描边标签:addShape(roundRect,{fill:{color:'none'},line:{color:C.mGreen,width:1}})
           + addText(绿色)

注意:PPTX 中衬线字体用 'Georgia';大量留白通过坐标间距体现

# 五、内容要求
- 根据「{{主题}}」设计 {{N}} 页故事型/品牌型 PPT
- 文案精炼,每页不超过 80 字(不含标题)
- 大量留白,视觉舒适,不追求信息密度
- 语言温暖、有人情味,避免商务黑话
- 数据真实可信(使用示意数据时标注)

# 六、交付
直接输出完整 .html 文件代码(单一代码块),确保:
- 米白暖色自然风格全局一致
- 有机圆形装饰元素正确渲染
- 导出 PPTX 文件名「{{主题}}.pptx」

---
主题 = "{{在此填写,如:绿色农场品牌故事}}"
N = {{页数,建议8-10}}
```

---

## 📋 快速使用参考表

| 风格 | 适用场景 | 主色调 | 视觉特点 |
|------|---------|--------|---------|
| **科技蓝商务风** | 企业汇报、技术培训、产品发布 | #1a6bff | 专业、权威、信息密度高 |
| **Apple 极简风** | 产品演示、创业路演、设计提案 | 黑白灰 | 极简、高级、留白多 |
| **暗黑科技风** | 技术分享、Hacker 风、网络安全 | #00d4ff + #7b2fff | 科幻、炫酷、视觉冲击 |
| **数据报告风** | 运营分析、季度报告、数据洞察 | #4e85fd | Dashboard、数据驱动 |
| **教育培训风** | 课程课件、知识科普、技能培训 | #f97316(橙色) | 友好、清晰、易读性强 |
| **简约自然风** | 品牌故事、环保主题、人文内容 | #2d5a27(深绿) | 温暖、有机、高留白 |

> 💡 **使用方法**:选择对应风格的提示词,填入 `主题` 和 `N`(页数),发给 AI 即可生成。

 

 
 
 
 

posted on 2026-04-24 09:33  GKLBB  阅读(42)  评论(0)    收藏  举报