-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathindex.html
More file actions
2269 lines (2090 loc) · 172 KB
/
Copy pathindex.html
File metadata and controls
2269 lines (2090 loc) · 172 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Frontend Slides:揭秘内部原理</title>
<!-- Google Fonts: Bricolage Grotesque · DM Sans · JetBrains Mono -->
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Bricolage+Grotesque:opsz,wght@12..96,400;12..96,600;12..96,700;12..96,800&family=DM+Sans:ital,opsz,wght@0,9..40,300;0,9..40,400;0,9..40,500;0,9..40,600;0,9..40,700;1,9..40,400;1,9..40,500&family=JetBrains+Mono:wght@400;500;600&display=swap" rel="stylesheet">
<link rel="stylesheet" href="styles.css">
<!--
CUSTOMIZE PER COURSE — change only the three accent variables below.
Options:
vermillion #D94F30 / #C4432A / #FDEEE9 / #E8836C (default)
coral #E06B56 / #C85A47 / #FDECEA / #E89585
teal #2A7B9B / #1F6280 / #E4F2F7 / #5A9DB8
amber #D4A843 / #BF9530 / #FDF5E0 / #E0C070
forest #2D8B55 / #226B41 / #E8F5EE / #5AAD7A
-->
<style>
:root {
--color-accent: #D94F30;
--color-accent-hover: #C4432A;
--color-accent-light: #FDEEE9;
--color-accent-muted: #E8836C;
/* 中文字体 fallback:英文用 DM Sans / Bricolage,中文回落到苹方等系统字体 */
--font-display: 'Bricolage Grotesque', 'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei', Georgia, serif;
--font-body: 'DM Sans', -apple-system, 'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei', sans-serif;
}
</style>
<script src="main.js" defer></script>
</head>
<body>
<nav class="nav" id="nav">
<div class="progress-bar" id="progress-bar" role="progressbar" aria-valuenow="0" aria-valuemin="0" aria-valuemax="100"></div>
<div class="nav-inner">
<a class="nav-title" href="../" style="text-decoration: none;">← Code Course Atlas</a>
<div class="nav-dots" id="nav-dots" role="tablist">
<button class="nav-dot" data-target="module-1" data-tooltip="用户旅程" role="tab" aria-label="模块 1:用户旅程"></button>
<button class="nav-dot" data-target="module-2" data-tooltip="认识角色" role="tab" aria-label="模块 2:认识角色"></button>
<button class="nav-dot" data-target="module-3" data-tooltip="渐进式披露" role="tab" aria-label="模块 3:渐进式披露"></button>
<button class="nav-dot" data-target="module-4" data-tooltip="固定舞台" role="tab" aria-label="模块 4:固定舞台"></button>
<button class="nav-dot" data-target="module-5" data-tooltip="展示而非讲述" role="tab" aria-label="模块 5:展示而非讲述"></button>
<button class="nav-dot" data-target="module-6" data-tooltip="出错时刻" role="tab" aria-label="模块 6:出错时刻"></button>
</div>
<a class="language-switch" href="../frontend-slides-course-en/index.html">EN</a>
</div>
</nav>
<main id="main">
<!-- modules/*.html content is assembled here by build.sh -->
<section class="module" id="module-1" style="background: var(--color-bg-warm)">
<div class="module-content">
<header class="module-header animate-in">
<span class="module-number">01</span>
<h1 class="module-title">用户旅程</h1>
<p class="module-subtitle">从一句话到一套打磨好的演示文稿——AI 走的是一条六阶段流水线。</p>
</header>
<div class="module-body">
<!-- SCREEN 1: The hook + the reframe -->
<section class="screen animate-in">
<h2 class="screen-heading">输入一句话,得到一套演示文稿。</h2>
<p class="text-lg">你输入 <em>make me a pitch deck for my AI startup</em>,几分钟后,一套打磨过、带动画的 <span class="term" data-definition="HTML(超文本标记语言)是每个网页的骨架——它定义页面结构:标题、段落、图片、按钮。你访问的每个网站,底层都是 HTML。">HTML</span> 演示文稿就在浏览器里打开了。下面是它刚刚跑完的那条流水线。</p>
<div class="flow-steps" style="margin: var(--space-8) 0;">
<div class="flow-step">
<div class="flow-step-num">1</div>
<p>你输入一句话</p>
</div>
<div class="flow-arrow">→</div>
<div class="flow-step">
<div class="flow-step-num">2</div>
<p>AI <span class="term" data-definition="agent(智能体)是一种会话式 AI,能读指令、写代码、替你执行命令——像一个不用睡觉、照着菜谱做菜的实习开发。">agent</span> 运行 <span class="term" data-definition="skill 是一文件夹的指令,教 AI agent 怎么完成一项具体工作——像一本菜谱,AI 一步一步照着做。本仓库就是一个 skill,不是一个 app。">skill</span></p>
</div>
<div class="flow-arrow">→</div>
<div class="flow-step">
<div class="flow-step-num">3</div>
<p>一套活的演示文稿在浏览器里打开</p>
</div>
</div>
<div class="callout callout-accent">
<div class="callout-icon">💡</div>
<div class="callout-content">
<strong class="callout-title">噢——这不是一个 app。</strong>
<p>整个仓库是一个 <em>skill</em>:一组教 AI agent 怎么做演示文稿的指令。AI agent 是引擎,<code>SKILL.md</code> 是它照着做的菜谱。没有东西会自己跑起来——是 agent 读菜谱、动手干活。</p>
</div>
</div>
</section>
<!-- SCREEN 2: The 6-phase map -->
<section class="screen animate-in">
<h2 class="screen-heading">流水线一览</h2>
<p>这份菜谱有六个 <span class="term" data-definition="phase 是 skill 工作流里编号的一步——Phase 0、Phase 1,依此类推。每个 phase 只干一件事,然后把接力棒交给下一个,像流水线上的工位。">phases</span>。每个干一件事,然后交棒。</p>
<div class="step-cards" style="margin-top: var(--space-6);">
<div class="step-card">
<div class="step-num">1</div>
<div class="step-body">
<strong>识别 — Phase 0</strong>
<p>搞清楚用户要什么:新建一套、转换 <span class="term" data-definition=".pptx 文件是 Microsoft PowerPoint 演示文稿——PowerPoint 保存的二进制格式。转换它意味着把每张幻灯片变成 HTML。">.pptx</span>,还是增强已有的。</p>
</div>
</div>
<div class="step-card">
<div class="step-num">2</div>
<div class="step-body">
<strong>内容 — Phase 1</strong>
<p>一次性问四个问题:目的、长度、内容、密度。</p>
</div>
</div>
<div class="step-card">
<div class="step-num">3</div>
<div class="step-body">
<strong>风格 — Phase 2</strong>
<p>生成三个视觉预览。用户靠看选,不靠描述。</p>
</div>
</div>
<div class="step-card">
<div class="step-num">4</div>
<div class="step-body">
<strong>生成 — Phase 3</strong>
<p>写一个自包含的 <code>.html</code> 文件,所有 <span class="term" data-definition="CSS(层叠样式表)是控制东西长什么样的语言——颜色、字体、大小、布局。如果 HTML 是骨架,CSS 就是穿的衣服。">CSS</span> 和 <span class="term" data-definition="JS(JavaScript)是让东西能交互的语言——点击、动画、响应。如果 HTML 是骨架、CSS 是衣服,JS 就是肌肉。">JS</span> 全部 <span class="term" data-definition="inline 指直接写在同一个文件里,不从别处加载。inline 的 CSS/JS 就在 HTML 内部,无需另外下载任何东西。">inline</span>。</p>
</div>
</div>
<div class="step-card">
<div class="step-num">5</div>
<div class="step-body">
<strong>交付 — Phase 5</strong>
<p>在浏览器里打开它。告诉用户怎么导航、怎么改。</p>
</div>
</div>
<div class="step-card">
<div class="step-num">6</div>
<div class="step-body">
<strong>分享 — Phase 6</strong>
<p>可选:<span class="term" data-definition="deploy 指把你的文件发布到一台 web 服务器上,任何拿到 URL 的人都能在浏览器里查看——像把一幅画挂到公共画廊,而不是留在自己画室里。">deploy</span> 到一个 URL,或导出 <span class="term" data-definition="PDF(便携文档格式)是一种固定版式的文件——所见即所印。适合把演示文稿当作只读文档分享,在哪儿看都长得一样。">PDF</span>。</p>
</div>
</div>
</div>
</section>
<!-- SCREEN 3: The hero flow animation -->
<section class="screen animate-in">
<h2 class="screen-heading">一步步看完整段旅程</h2>
<p>点 <em>下一步</em>,跟着一句话走完整条流水线。</p>
<div class="flow-animation" data-steps='[
{"highlight":"flow-actor-1","label":"你输入:make me a pitch deck for my AI startup"},
{"highlight":"flow-actor-2","label":"AI 判断:新建演示文稿(Mode A)","packet":true,"from":"actor-1","to":"actor-2"},
{"highlight":"flow-actor-3","label":"一次问 4 个问题:目的、长度、内容、密度","packet":true,"from":"actor-2","to":"actor-3"},
{"highlight":"flow-actor-4","label":"生成 3 个视觉预览供对比","packet":true,"from":"actor-3","to":"actor-4"},
{"highlight":"flow-actor-4","label":"你靠看选一个喜欢的,不用描述"},
{"highlight":"flow-actor-5","label":"读入所选风格的完整设计菜谱","packet":true,"from":"actor-4","to":"actor-5"},
{"highlight":"flow-actor-5","label":"写一个自包含的 .html 文件,CSS/JS 全部 inline"},
{"highlight":"flow-actor-6","label":"在浏览器里打开它","packet":true,"from":"actor-5","to":"actor-6"},
{"highlight":"flow-actor-7","label":"可选:deploy 到 URL 或导出 PDF","packet":true,"from":"actor-6","to":"actor-7"}
]'>
<div class="flow-actors">
<div class="flow-actor" id="flow-actor-1">
<div class="flow-actor-icon" style="background: var(--color-actor-1)">U</div>
<span>你</span>
</div>
<div class="flow-actor" id="flow-actor-2">
<div class="flow-actor-icon" style="background: var(--color-actor-2)">0</div>
<span>识别</span>
</div>
<div class="flow-actor" id="flow-actor-3">
<div class="flow-actor-icon" style="background: var(--color-actor-3)">1</div>
<span>内容</span>
</div>
<div class="flow-actor" id="flow-actor-4">
<div class="flow-actor-icon" style="background: var(--color-actor-4)">2</div>
<span>风格</span>
</div>
<div class="flow-actor" id="flow-actor-5">
<div class="flow-actor-icon" style="background: var(--color-actor-5)">3</div>
<span>生成</span>
</div>
<div class="flow-actor" id="flow-actor-6">
<div class="flow-actor-icon" style="background: var(--color-actor-2)">5</div>
<span>交付</span>
</div>
<div class="flow-actor" id="flow-actor-7">
<div class="flow-actor-icon" style="background: var(--color-actor-3)">6</div>
<span>分享</span>
</div>
</div>
<div class="flow-packet" id="flow-packet"></div>
<div class="flow-step-label" id="flow-label">点「下一步」开始</div>
<div class="flow-controls">
<button class="btn flow-next-btn">下一步</button>
<button class="btn flow-reset-btn">重新开始</button>
<span class="flow-progress"></span>
</div>
</div>
<div class="callout callout-info" style="margin-top: var(--space-8);">
<div class="callout-icon">🧭</div>
<div class="callout-content">
<strong class="callout-title">为什么这很重要</strong>
<p>知道有哪些 phase,你就能在对的时机 <em>转向</em> AI(跳过风格发现,我要 Bold Signal),也能在它卡住时 <em>诊断</em>(它在 Phase 2 里打转——它根本没问密度)。</p>
</div>
</div>
</section>
<!-- SCREEN 4: Phase 0 routing -->
<section class="screen animate-in">
<h2 class="screen-heading">Phase 0 选一条道走</h2>
<p>在一切开始之前,AI 先识别你想要三种模式里的哪一种——这个选择决定了旅程接下来往哪儿走。</p>
<div class="pattern-cards" style="margin-top: var(--space-6);">
<div class="pattern-card" style="border-top: 3px solid var(--color-actor-2)">
<div class="pattern-icon" style="background: var(--color-actor-2)">A</div>
<h4 class="pattern-title">Mode A — 新建演示文稿</h4>
<p class="pattern-desc">从零开始。进入 Phase 1(内容提问)。</p>
</div>
<div class="pattern-card" style="border-top: 3px solid var(--color-actor-4)">
<div class="pattern-icon" style="background: var(--color-actor-4)">B</div>
<h4 class="pattern-title">Mode B — PPT 转换</h4>
<p class="pattern-desc">转换一个 .pptx 文件。直接跳到 Phase 4。</p>
</div>
<div class="pattern-card" style="border-top: 3px solid var(--color-actor-5)">
<div class="pattern-icon" style="background: var(--color-actor-5)">C</div>
<h4 class="pattern-title">Mode C — 增强</h4>
<p class="pattern-desc">改进已有的 HTML 演示文稿。读它、理解它、增强它。</p>
</div>
</div>
<p class="text-sm" style="margin-top: var(--space-4); color: var(--color-text-secondary);">注意 Mode B 完全跳过了 Phase 1–3——内容与风格已经在 PowerPoint 文件里了。</p>
</section>
<!-- SCREEN 5: Phase 3 — the stage that scales -->
<section class="screen animate-in">
<h2 class="screen-heading"><span class="term" data-definition="16:9 是电视、YouTube 和 PowerPoint 通用的标准宽屏宽高比——宽 16 份、高 9 份。本 skill 把每套演示文稿都锁死成这个形状。">16:9</span> 舞台的把戏</h2>
<p>每套演示文稿都用一个固定的 1920×1080 画布,整体按比例缩小去适配你的 <span class="term" data-definition="viewport 是浏览器窗口里网页实际可见的那块矩形区域。你拖动窗口大小,viewport 就跟着变。">viewport</span>。下面是干这件事的真实代码。</p>
<div class="translation-block animate-in">
<div class="translation-code">
<span class="translation-label">CODE</span>
<pre><code><span class="code-line"><span class="code-function">setupStageScale</span>() {</span>
<span class="code-line"> <span class="code-keyword">const</span> scale = () <span class="code-operator">=></span> {</span>
<span class="code-line"> <span class="code-keyword">const</span> factor = <span class="code-function">Math.min</span>(window.innerWidth / <span class="code-number">1920</span>, window.innerHeight / <span class="code-number">1080</span>);</span>
<span class="code-line"> <span class="code-keyword">const</span> x = (window.innerWidth - <span class="code-number">1920</span> * factor) / <span class="code-number">2</span>;</span>
<span class="code-line"> <span class="code-keyword">const</span> y = (window.innerHeight - <span class="code-number">1080</span> * factor) / <span class="code-number">2</span>;</span>
<span class="code-line"> <span class="code-keyword">this</span>.stage.style.<span class="code-property">transform</span> = <span class="code-string">`translate(${x}px, ${y}px) scale(${factor})`</span>;</span>
<span class="code-line"> };</span>
<span class="code-line"> <span class="code-function">scale</span>();</span>
<span class="code-line"> window.<span class="code-function">addEventListener</span>(<span class="code-string">'resize'</span>, scale);</span>
<span class="code-line">}</span>
</code></pre>
</div>
<div class="translation-english">
<span class="translation-label">大白话</span>
<div class="translation-lines">
<p class="tl">一个函数,给幻灯片舞台装上自动缩放。</p>
<p class="tl">定义一个叫 <code>scale</code> 的小帮手,需要重新适配时随时调用。</p>
<p class="tl">在「按宽适配」和「按高适配」里挑小的那个,保证 1920×1080 画布永远不溢出。</p>
<p class="tl">水平居中——多出来的宽度左右平分(两边留黑边)。</p>
<p class="tl">垂直居中——多出来的高度上下平分(上下留黑边)。</p>
<p class="tl">应用上去:先按 x、y <span class="term" data-definition="transform 是一个 CSS 属性,能在不影响周围元素的情况下移动、旋转或缩放某个元素——像揭起一张贴纸,再重新贴到页面上。">transform</span> 舞台,再按 factor <span class="term" data-definition="scale 是一种 transform 值,按倍数放大或缩小元素——scale(0.5) 缩到一半,scale(2) 放大一倍。">scale</span> 它,一步到位。</p>
<p class="tl">小帮手结束。</p>
<p class="tl">立刻跑一次,让演示文稿一加载就贴合。</p>
<p class="tl">之后每次窗口尺寸变了再跑一次,让演示文稿始终贴合。</p>
<p class="tl"><code>setupStageScale</code> 结束。</p>
</div>
</div>
</div>
</section>
<!-- SCREEN 6: The five non-negotiables -->
<section class="screen animate-in">
<h2 class="screen-heading">AI 绝不破的五条规矩</h2>
<p>这几条原则贯穿每一个 phase。如果 AI 开始产出千篇一律的东西,或者拆成多个文件,那一定是其中某条被破了。</p>
<div class="pattern-cards" style="margin-top: var(--space-6);">
<div class="pattern-card" style="border-top: 3px solid var(--color-actor-1)">
<div class="pattern-icon" style="background: var(--color-actor-1)">1</div>
<h4 class="pattern-title">零依赖</h4>
<p class="pattern-desc">单一 HTML 文件,CSS/JS 全 inline。不用 <span class="term" data-definition="npm 是 JavaScript 的包管理器——一个下载第三方代码库供你项目使用的工具。本 skill 禁用它:一切都自包含。">npm</span>,不用 <span class="term" data-definition="build tools 是在代码发布前处理源码的程序——打包、压缩、转译新语法。本项目完全不用,让产物保持简单。">build tools</span>。</p>
</div>
<div class="pattern-card" style="border-top: 3px solid var(--color-actor-2)">
<div class="pattern-icon" style="background: var(--color-actor-2)">2</div>
<h4 class="pattern-title">Show, Don't Tell</h4>
<p class="pattern-desc">生成视觉预览,而不是抽象选项。人是在「看见」的过程中发现想要什么的。</p>
</div>
<div class="pattern-card" style="border-top: 3px solid var(--color-actor-3)">
<div class="pattern-icon" style="background: var(--color-actor-3)">3</div>
<h4 class="pattern-title">有辨识度的设计</h4>
<p class="pattern-desc">不要千篇一律的 AI 套路。每套演示文稿都要像量身打造的。</p>
</div>
<div class="pattern-card" style="border-top: 3px solid var(--color-actor-4)">
<div class="pattern-icon" style="background: var(--color-actor-4)">4</div>
<h4 class="pattern-title">Progressive Disclosure</h4>
<p class="pattern-desc">先读轻量的风格索引。等用户选了 <span class="term" data-definition="template 是一份预先做好的风格菜谱:一个文件夹,里面有 design.md、字体和配色规则,AI 拿它当一套演示文稿的起点。">template</span>,再去加载完整的 <span class="term" data-definition="design.md 是每个 template 文件夹里的一个 Markdown 文件,包含那一种风格的完整设计菜谱——颜色、字体、间距规则。">design.md</span>。</p>
</div>
<div class="pattern-card" style="border-top: 3px solid var(--color-actor-5)">
<div class="pattern-icon" style="background: var(--color-actor-5)">5</div>
<h4 class="pattern-title">固定 16:9 舞台</h4>
<p class="pattern-desc">每套演示文稿都用 1920×1080 画布整体缩放。在任何屏幕(包括手机)上幻灯片都保持 16:9,不为了适配设备而重新排版内容。</p>
</div>
</div>
</section>
<!-- SCREEN 7: Phase 5 delivery -->
<section class="screen animate-in">
<h2 class="screen-heading">交付:方向盘交给你</h2>
<p>Phase 5 把钥匙交到你手上。AI 收拾干净、打开文件、告诉你怎么开。</p>
<div class="step-cards" style="margin-top: var(--space-6);">
<div class="step-card">
<div class="step-num">1</div>
<div class="step-body">
<strong>收拾干净</strong>
<p>如果有 <code>.frontend-slides/slide-previews/</code> 就删掉——不留临时草稿。</p>
</div>
</div>
<div class="step-card">
<div class="step-num">2</div>
<div class="step-body">
<strong>打开</strong>
<p>运行 <code>open [filename].html</code>,在浏览器里启动演示文稿。</p>
</div>
</div>
<div class="step-card">
<div class="step-num">3</div>
<div class="step-body">
<strong>交代清楚</strong>
<p>告诉你文件位置、风格名、幻灯片张数。说明导航:方向键、空格、滑动。说明怎么改:颜色用 <span class="term" data-definition=":root 是一个 CSS 选择器,指向页面最顶层元素。在这里定义的变量——比如颜色和字体——整个演示文稿都能用。">:root</span> CSS 变量,字体用 font link,动画用 <span class="term" data-definition=".reveal 是 AI 用来标记「该动画进场」元素的 CSS class——通常是幻灯片出现时淡入或滑入。">.reveal</span> class。</p>
</div>
</div>
</div>
</section>
<!-- SCREEN 8: Quiz -->
<section class="screen animate-in">
<h2 class="screen-heading">测测你的转向直觉</h2>
<p>三个场景。选一个能证明你清楚每个 phase 干什么的答案。</p>
<div class="quiz-container" id="quiz-module1" style="margin-top: var(--space-6);">
<div class="quiz-question-block"
data-correct="option-c"
data-explanation-right="对——Phase 2 就是发现风格。如果你已经知道自己要什么风格,告诉 AI 跳过预览,直接带着选好的 template 进 Phase 3。"
data-explanation-wrong="不太对。Phase 2 是 AI 通过给你看视觉预览来发现你想要什么风格的阶段。如果你已经知道风格了,那该跳过或快进的就是这个 phase。">
<h3 class="quiz-question">你已经非常确定要哪种风格(Bold Signal)。该让 AI 跳过或快进哪个 phase?</h3>
<div class="quiz-options">
<button class="quiz-option" data-value="option-a" onclick="selectOption(this)">
<div class="quiz-option-radio"></div>
<span>Phase 0 — 识别</span>
</button>
<button class="quiz-option" data-value="option-b" onclick="selectOption(this)">
<div class="quiz-option-radio"></div>
<span>Phase 1 — 内容</span>
</button>
<button class="quiz-option" data-value="option-c" onclick="selectOption(this)">
<div class="quiz-option-radio"></div>
<span>Phase 2 — 风格</span>
</button>
<button class="quiz-option" data-value="option-d" onclick="selectOption(this)">
<div class="quiz-option-radio"></div>
<span>Phase 5 — 交付</span>
</button>
</div>
<div class="quiz-feedback"></div>
</div>
<div class="quiz-question-block"
data-correct="option-a"
data-explanation-right="对——Phase 1 必须一次问完四个问题(目的、长度、内容、密度),不能一个一个挤牙膏。它破的就是这条规矩。"
data-explanation-wrong="不太对。想想哪个 phase 是从你这里收集需求的。Phase 1 要求把所有问题一起问——一个一个问,正是这套 skill 设计上要避免的失败模式。">
<h3 class="quiz-question">AI 老是一个一个地问颜色、字体。它破了哪个 phase 的规矩?</h3>
<div class="quiz-options">
<button class="quiz-option" data-value="option-a" onclick="selectOption(this)">
<div class="quiz-option-radio"></div>
<span>Phase 1 — 一次问完所有问题</span>
</button>
<button class="quiz-option" data-value="option-b" onclick="selectOption(this)">
<div class="quiz-option-radio"></div>
<span>Phase 0 — 先识别模式</span>
</button>
<button class="quiz-option" data-value="option-c" onclick="selectOption(this)">
<div class="quiz-option-radio"></div>
<span>Phase 3 — 生成一个 HTML 文件</span>
</button>
<button class="quiz-option" data-value="option-d" onclick="selectOption(this)">
<div class="quiz-option-radio"></div>
<span>Phase 5 — 清理预览</span>
</button>
</div>
<div class="quiz-feedback"></div>
</div>
<div class="quiz-question-block"
data-correct="option-c"
data-explanation-right="对——Phase 0 识别出 Mode B(PPT 转换),直接路由到 Phase 4,完全跳过内容与风格的发现阶段。"
data-explanation-wrong="不太对。你把 .pptx 交给 AI 时,Phase 0 会把它归为 Mode B,跳到 Phase 4——把 PowerPoint 幻灯片转成 HTML 的那个阶段。内容和风格已经存在于文件里了。">
<h3 class="quiz-question">你把一个 .pptx 文件交给 AI。它会跳到哪个 phase?</h3>
<div class="quiz-options">
<button class="quiz-option" data-value="option-a" onclick="selectOption(this)">
<div class="quiz-option-radio"></div>
<span>Phase 1 — 内容</span>
</button>
<button class="quiz-option" data-value="option-b" onclick="selectOption(this)">
<div class="quiz-option-radio"></div>
<span>Phase 2 — 风格</span>
</button>
<button class="quiz-option" data-value="option-c" onclick="selectOption(this)">
<div class="quiz-option-radio"></div>
<span>Phase 4 — 转换</span>
</button>
<button class="quiz-option" data-value="option-d" onclick="selectOption(this)">
<div class="quiz-option-radio"></div>
<span>Phase 5 — 交付</span>
</button>
</div>
<div class="quiz-feedback"></div>
</div>
<button class="quiz-check-btn" onclick="checkQuiz('quiz-module1')">检查答案</button>
<button class="quiz-reset-btn" onclick="resetQuiz('quiz-module1')">重试</button>
</div>
</section>
<!-- SCREEN 9: Transition to Module 2 -->
<section class="screen animate-in">
<h2 class="screen-heading">认识演职员表</h2>
<p>那条流水线由一组文件撑起来——每个都干一件具体的事。下一模块,我们推开工作室的门,挨个认识它们。</p>
<div class="callout callout-info" style="margin-top: var(--space-6);">
<div class="callout-icon">📂</div>
<div class="callout-content">
<strong class="callout-title">下一站:Module 2 — 认识演职员</strong>
<p><code>SKILL.md</code> 是工作室经理,但它不是一个人在干活。仓库里有 template 文件夹、风格索引,还有每种长相各一份的 <code>design.md</code>。我们会顺一遍谁读什么、什么时候读。</p>
</div>
</div>
</section>
</div>
</div>
</section>
<section class="module" id="module-2" style="background: var(--color-bg)">
<div class="module-content">
<header class="module-header animate-in">
<span class="module-number">02</span>
<h1 class="module-title">认识全体演员</h1>
<p class="module-subtitle">模块 1 里那位片场总管并不是一个人在干活。每个阶段背后都有一个专门的文件——一个只在需要它那门手艺时才被呼叫出场的部门。</p>
</header>
<div class="module-body">
<!-- SCREEN 1: Hook + Pattern Cards -->
<section class="screen animate-in">
<h2 class="screen-heading">是剧组,不是独角戏</h2>
<p>把 <span class="term" data-definition="一组文件组成的文件夹,告诉 AI agent 怎么完成一项专门的工作——就像一本剧组手册,AI 上工前先读它。">skill repo</span> 想象成一个片场。<code>SKILL.md</code> 是<strong>导演</strong>,每一个镜头都由它发号施令。其他支持文件则是各个专业部门——服装、高定工坊、舞台吊装、后期——每个部门都只在某个特定时刻被呼叫上场。</p>
<p>知道哪个文件管哪件事,你就能告诉 AI 该<em>去哪儿</em>改东西。下面是五个部门:</p>
<div class="pattern-cards">
<div class="pattern-card" style="border-top: 3px solid var(--color-actor-1)">
<div class="pattern-icon" style="background: var(--color-actor-1)">🎬</div>
<h4 class="pattern-title">导演</h4>
<p class="pattern-desc"><code>SKILL.md</code> —— 发号施令,按分镜单走流程。每个 <span class="term" data-definition="流水线上的一个编号步骤。这个 skill 把做演示文稿拆成 6 个阶段,从需求到分享。">phase</span> 都会呼叫它。</p>
</div>
<div class="pattern-card" style="border-top: 3px solid var(--color-actor-4)">
<div class="pattern-icon" style="background: var(--color-actor-4)">👔</div>
<h4 class="pattern-title">服装部</h4>
<p class="pattern-desc"><code>STYLE_PRESETS.md</code> —— 12 套安全、即开即穿的造型,含配色与字体。在第 2 阶段(选风格)呼叫。</p>
</div>
<div class="pattern-card" style="border-top: 3px solid var(--color-actor-3)">
<div class="pattern-icon" style="background: var(--color-actor-3)">🎨</div>
<h4 class="pattern-title">高定工坊</h4>
<p class="pattern-desc"><code>bold-template-pack/</code> —— 一个装着 34 套设计师系列的 <span class="term" data-definition="法语词,原指艺术家的作坊或工作室——在时尚界,特指手工打造独一无二单品的高端工坊。">atelier</span>。在第 2–3 阶段呼叫。</p>
</div>
<div class="pattern-card" style="border-top: 3px solid var(--color-actor-2)">
<div class="pattern-icon" style="background: var(--color-actor-2)">🎭</div>
<h4 class="pattern-title">舞台吊装</h4>
<p class="pattern-desc"><code>viewport-base.css</code> —— 搭起固定的 1920×1080 舞台。第 3 阶段(生成)每次都呼叫。</p>
</div>
<div class="pattern-card" style="border-top: 3px solid var(--color-actor-5)">
<div class="pattern-icon" style="background: var(--color-actor-5)">🎞️</div>
<h4 class="pattern-title">后期</h4>
<p class="pattern-desc"><code>scripts/</code> —— 提取、导出、<span class="term" data-definition="把你的项目发布到互联网上,让别人能访问——就像从彩排厅搬到首演之夜。">deploy</span>。只在第 4 和第 6 阶段呼叫。</p>
</div>
</div>
</section>
<!-- SCREEN 2: Cast List Table -->
<section class="screen animate-in">
<h2 class="screen-heading">演员表</h2>
<p>这张表就在 <code>SKILL.md</code> 内部——导演的分镜单,记着谁干什么、什么时候被加载:</p>
<div class="translation-block animate-in">
<div class="translation-code">
<span class="translation-label">SKILL.md</span>
<pre><code><span class="code-line">| File | Purpose | When to Read |</span>
<span class="code-line">| -------------------------------------------------- | -------------------------------------------------------------------- | ------------------------- |</span>
<span class="code-line">| STYLE_PRESETS.md | 12 curated visual presets with colors, fonts, and signature elements | Phase 2 (style selection) |</span>
<span class="code-line">| bold-template-pack/selection-index.json | Compact bold template metadata for candidate selection | Phase 2 (style selection) |</span>
<span class="code-line">| bold-template-pack/templates/*/preview.md | Lightweight style cards for shortlisted bold title previews | Phase 2 after shortlisting |</span>
<span class="code-line">| bold-template-pack/templates/*/design.md | Detailed design-system docs for the selected bold template only | Phase 3 after user selection |</span>
<span class="code-line">| viewport-base.css | Mandatory fixed-stage CSS — copy into every presentation | Phase 3 (generation) |</span>
<span class="code-line">| html-template.md | HTML structure, JS features, code quality standards | Phase 3 (generation) |</span>
<span class="code-line">| animation-patterns.md | CSS/JS animation snippets and effect-to-feeling guide | Phase 3 (generation) |</span>
<span class="code-line">| scripts/extract-pptx.py | Python script for PPT content extraction | Phase 4 (conversion) |</span>
<span class="code-line">| scripts/deploy.sh | Deploy slides to Vercel for instant sharing | Phase 6 (sharing) |</span>
<span class="code-line">| scripts/export-pdf.sh | Export slides to PDF | Phase 6 (sharing) |</span></code></pre>
</div>
<div class="translation-english">
<span class="translation-label">怎么读</span>
<div class="translation-lines">
<p class="tl"><strong>风格部门</strong> —— <code>STYLE_PRESETS.md</code> 和 <code>bold-template-pack/</code> 这条链(index → preview → design)都在第 2 阶段读取,也就是 AI 在挑造型的时候。</p>
<p class="tl"><strong>舞台与剧本</strong> —— <code>viewport-base.css</code>、<code>html-template.md</code>、<code>animation-patterns.md</code> 在第 3 阶段读取,也就是 AI 真正生成幻灯片的时候。</p>
<p class="tl"><strong>后期</strong> —— 三个脚本只在第 4 阶段(把 <span class="term" data-definition="微软 PowerPoint 用来保存演示文稿的文件格式。它把幻灯片、文字、图片和备注打包成一个文件。">.pptx</span> 转换出来)和第 6 阶段(分享)才被读取。其余时间它们都闲着。</p>
<p class="tl">每个文件<strong>只干一件事,只在某个特定时刻被加载</strong>。整套设计就是这样。</p>
</div>
</div>
</div>
</section>
<!-- SCREEN 3: Group Chat Animation (Hero) -->
<section class="screen animate-in">
<h2 class="screen-heading">剧组碰头会</h2>
<p>一个新演示文稿的需求刚到。看每个文件依次自我介绍——顺序正是它们被呼叫上场的顺序:</p>
<div class="chat-window" id="chat-module2">
<div class="chat-messages">
<div class="chat-message" data-msg="0" data-sender="skill" style="display:none">
<div class="chat-avatar" style="background: var(--color-actor-1)">S</div>
<div class="chat-bubble">
<span class="chat-sender" style="color: var(--color-actor-1)">SKILL.md</span>
<p>好了各位——新演示文稿需求到了。第 2 阶段需要风格选项。谁上?</p>
</div>
</div>
<div class="chat-message" data-msg="1" data-sender="presets" style="display:none">
<div class="chat-avatar" style="background: var(--color-actor-4)">P</div>
<div class="chat-bubble">
<span class="chat-sender" style="color: var(--color-actor-4)">STYLE_PRESETS.md</span>
<p>我这里有 12 套经过验证的安全预设,随时能用——Bold Signal、Notebook Tabs、Neon Cyber……</p>
</div>
</div>
<div class="chat-message" data-msg="2" data-sender="index" style="display:none">
<div class="chat-avatar" style="background: var(--color-actor-3)">I</div>
<div class="chat-bubble">
<span class="chat-sender" style="color: var(--color-actor-3)">selection-index.json</span>
<p>等一下——我是全部 34 套 bold 模板的索引。先读我,我个头小。我会告诉你每一套的情绪和正式程度。</p>
</div>
</div>
<div class="chat-message" data-msg="3" data-sender="preview" style="display:none">
<div class="chat-avatar" style="background: var(--color-actor-2)">V</div>
<div class="chat-bubble">
<span class="chat-sender" style="color: var(--color-actor-2)">preview.md</span>
<p>等索引筛出几套候选后,我就是那张轻量预览卡。看一眼就行,不用动真格。</p>
</div>
</div>
<div class="chat-message" data-msg="4" data-sender="design" style="display:none">
<div class="chat-avatar" style="background: var(--color-actor-5)">D</div>
<div class="chat-bubble">
<span class="chat-sender" style="color: var(--color-actor-5)">design.md</span>
<p>只有当用户选定某一套模板之后——我才加载。我是完整的设计配方。体量大,所以最后读我。</p>
</div>
</div>
<div class="chat-message" data-msg="5" data-sender="viewport" style="display:none">
<div class="chat-avatar" style="background: var(--color-actor-2)">C</div>
<div class="chat-bubble">
<span class="chat-sender" style="color: var(--color-actor-2)">viewport-base.css</span>
<p>只要一开始生成,我就是强制项。我搭起 1920×1080 的舞台。每一份演示文稿都要把我完整复制进去。</p>
</div>
</div>
<div class="chat-message" data-msg="6" data-sender="skill" style="display:none">
<div class="chat-avatar" style="background: var(--color-actor-1)">S</div>
<div class="chat-bubble">
<span class="chat-sender" style="color: var(--color-actor-1)">SKILL.md</span>
<p>完美。scripts/——待命等第 4 和第 6 阶段。除非有 .pptx 要处理或要分享,否则不呼叫你们。</p>
</div>
</div>
</div>
<div class="chat-typing" id="chat-module2-typing" style="display:none">
<div class="chat-avatar" id="chat-module2-typing-avatar">?</div>
<div class="chat-typing-dots">
<span class="typing-dot"></span>
<span class="typing-dot"></span>
<span class="typing-dot"></span>
</div>
</div>
<div class="chat-controls">
<button class="btn chat-next-btn">下一条消息</button>
<button class="btn chat-all-btn">全部播放</button>
<button class="btn chat-reset-btn">重播</button>
<span class="chat-progress"></span>
</div>
</div>
<p>注意每个文件身上穿的颜色。这些角色色在整个课程里保持一致——<span style="color: var(--color-actor-1); font-weight: 600;">SKILL.md 是朱红色</span>,<span style="color: var(--color-actor-4); font-weight: 600;">STYLE_PRESETS 是金黄色</span>,<span style="color: var(--color-actor-3); font-weight: 600;">索引是紫梅色</span>,<span style="color: var(--color-actor-2); font-weight: 600;">preview 和 viewport 是青色</span>,<span style="color: var(--color-actor-5); font-weight: 600;">design 和 scripts 是森林绿</span>。</p>
</section>
<!-- SCREEN 4: Visual File Tree -->
<section class="screen animate-in">
<h2 class="screen-heading">仓库结构</h2>
<p>这是实际的文件夹结构——每个文件配一句它干什么的:</p>
<div class="file-tree">
<div class="ft-file">
<span class="ft-name">SKILL.md</span>
<span class="ft-desc">导演——发号施令,按分镜单走流程</span>
</div>
<div class="ft-file">
<span class="ft-name">STYLE_PRESETS.md</span>
<span class="ft-desc">服装间——12 套安全、即开即穿的造型</span>
</div>
<div class="ft-file">
<span class="ft-name">viewport-base.css</span>
<span class="ft-desc">舞台吊装——搭起固定的 16:9 舞台</span>
</div>
<div class="ft-file">
<span class="ft-name">html-template.md</span>
<span class="ft-desc">剧本格式——每份演示文稿都要遵守的 <span class="term" data-definition="定义网页结构的语言——标题、段落、图片、链接。它是所有网站的地基骨架。">HTML</span> 结构</span>
</div>
<div class="ft-file">
<span class="ft-name">animation-patterns.md</span>
<span class="ft-desc">特效库——<span class="term" data-definition="控制网页外观的语言——颜色、字体、尺寸、布局。HTML 管结构,CSS 管刷漆和装饰。">CSS</span>/JS 动画片段</span>
</div>
<div class="ft-folder open">
<span class="ft-name">bold-template-pack/</span>
<span class="ft-desc">高级定制工坊——34 套设计师系列</span>
<div class="ft-children">
<div class="ft-file">
<span class="ft-name">selection-index.json</span>
<span class="ft-desc">目录册——全部 34 套模板的精简 <span class="term" data-definition="描述其他数据的数据——就像文件夹上的标签,不用打开就能知道里面是什么。一张照片的 metadata 可能包括日期、相机型号、地点。">metadata</span></span>
</div>
<div class="ft-folder open">
<span class="ft-name">templates/</span>
<span class="ft-desc">各个模板的文件夹</span>
<div class="ft-children">
<div class="ft-folder open">
<span class="ft-name">8-bit-orbit/ (each template)</span>
<span class="ft-desc">一个设计师系列</span>
<div class="ft-children">
<div class="ft-file">
<span class="ft-name">preview.md</span>
<span class="ft-desc">轻量风格卡——看一眼就行,不用动真格</span>
</div>
<div class="ft-file">
<span class="ft-name">design.md</span>
<span class="ft-desc">完整设计配方——最后才加载,只给被选中的那套</span>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="ft-folder open">
<span class="ft-name">scripts/</span>
<span class="ft-desc">后期制作间——提取、导出、部署</span>
<div class="ft-children">
<div class="ft-file">
<span class="ft-name">extract-pptx.py</span>
<span class="ft-desc">第 4 阶段——把内容从 .pptx 里抽出来</span>
</div>
<div class="ft-file">
<span class="ft-name">deploy.sh</span>
<span class="ft-desc">第 6 阶段——部署到 <span class="term" data-definition="一个托管网站和应用云平台——你把文件传上去,Vercel 给你一个任何人都能访问的公开网址。">Vercel</span> 用于分享</span>
</div>
<div class="ft-file">
<span class="ft-name">export-pdf.sh</span>
<span class="ft-desc">第 6 阶段——把幻灯片导出为 PDF</span>
</div>
</div>
</div>
</div>
</section>
<!-- SCREEN 5: JSON Metadata Card Translation -->
<section class="screen animate-in">
<h2 class="screen-heading">一张模板的 metadata 卡片</h2>
<p>在 <code>selection-index.json</code> 里,34 套模板每一套都有这样一张紧凑的小卡片。AI 读这些卡片来找候选——这时候还没加载任何大文件:</p>
<div class="translation-block animate-in">
<div class="translation-code">
<span class="translation-label">JSON</span>
<pre><code><span class="code-line"><span class="code-operator">{</span></span>
<span class="code-line"> <span class="code-property">"slug"</span>: <span class="code-string">"8-bit-orbit"</span>,</span>
<span class="code-line"> <span class="code-property">"name"</span>: <span class="code-string">"8-Bit Orbit"</span>,</span>
<span class="code-line"> <span class="code-property">"tagline"</span>: <span class="code-string">"Pixel-art neon arcade aesthetic on a deep navy void."</span>,</span>
<span class="code-line"> <span class="code-property">"mood"</span>: <span class="code-operator">[</span><span class="code-string">"retro-tech"</span>, <span class="code-string">"playful"</span>, <span class="code-string">"cyberpunk"</span>, <span class="code-string">"energetic"</span><span class="code-operator">]</span>,</span>
<span class="code-line"> <span class="code-property">"tone"</span>: <span class="code-operator">[</span><span class="code-string">"geeky"</span>, <span class="code-string">"neon"</span>, <span class="code-string">"rebellious"</span>, <span class="code-string">"sci-fi"</span><span class="code-operator">]</span>,</span>
<span class="code-line"> <span class="code-property">"formality"</span>: <span class="code-string">"low"</span>,</span>
<span class="code-line"> <span class="code-property">"density"</span>: <span class="code-string">"medium"</span>,</span>
<span class="code-line"> <span class="code-property">"scheme"</span>: <span class="code-string">"dark"</span>,</span>
<span class="code-line"> <span class="code-property">"best_for"</span>: <span class="code-string">"Anything that should feel like a CRT screen at 2am: cyberpunk, gaming, web3, indie dev tools, hackathon demos..."</span>,</span>
<span class="code-line"> <span class="code-property">"avoid_for"</span>: <span class="code-string">"Contexts where the dark neon palette would actively work against the message — quiet institutional finance disclosures, healthcare patient-facing materials, traditional luxury."</span>,</span>
<span class="code-line"> <span class="code-property">"preview_md"</span>: <span class="code-string">"bold-template-pack/templates/8-bit-orbit/preview.md"</span>,</span>
<span class="code-line"> <span class="code-property">"design_md"</span>: <span class="code-string">"bold-template-pack/templates/8-bit-orbit/design.md"</span></span>
<span class="code-line"><span class="code-operator">}</span></span></code></pre>
</div>
<div class="translation-english">
<span class="translation-label">大白话</span>
<div class="translation-lines">
<p class="tl"><strong>slug</strong> + <strong>name</strong> —— 模板的计算机 ID(一个 <span class="term" data-definition="一种简短、对 URL 友好的标识符,由小写字母和短横线组成——比如 '8-bit-orbit'。它是文件的小名,计算机用这个名字来引用文件。">slug</span>)和给人看的展示名。</p>
<p class="tl"><strong>tagline</strong> —— 一句话概括气质,AI 拿它和你的需求做匹配。</p>
<p class="tl"><strong>mood</strong> + <strong>tone</strong> —— 关键词标签,AI 拿它们跟你的需求 brief 对比。这里是"俏皮的赛博朋克",别处可能是"严肃的企业风"。</p>
<p class="tl"><strong>formality</strong> + <strong>density</strong> + <strong>scheme</strong> —— 几个快速旋钮:多正式、每页塞多少内容、浅色还是深色背景。</p>
<p class="tl"><strong>best_for</strong> —— 什么时候该选这套模板。AI 读这个来筛候选。</p>
<p class="tl"><strong>avoid_for</strong> —— 什么时候不该选。它能避免尴尬的错配(比如给医疗演示文稿配了霓虹街机风)。</p>
<p class="tl"><strong>preview_md</strong> + <strong>design_md</strong> —— 指向预览卡和完整设计配方的文件路径。AI 只在轮到的时候才顺着这些路径走——这就是那条链。</p>
</div>
</div>
</div>
<p>这整张卡片就是纯 <span class="term" data-definition="一种用文本存储结构化数据的格式,人和机器都能读——像一个标签贴得整整齐齐的文件柜,每个值都有自己的名字。">JSON</span> —— 一种 <span class="term" data-definition="一种把数据组织成带标签字段加值的格式——像一张表单,每个格子都有名字。AI 读这些字段来做决定。">structured data</span> 格式。没有样式,没有代码,只有事实。小到 AI 能一口气扫完全部 34 张。</p>
</section>
<!-- SCREEN 6: Python extract-pptx.py Translation -->
<section class="screen animate-in">
<h2 class="screen-heading">后期:转换一份 .pptx</h2>
<p>当用户上传一份旧的 PowerPoint 时,跑的就是 <code>scripts/extract-pptx.py</code> 这个文件。下面是核心循环——它遍历每一张幻灯片,把对象分成文字和图片两类:</p>
<div class="translation-block animate-in">
<div class="translation-code">
<span class="translation-label">Python</span>
<pre><code><span class="code-line"><span class="code-keyword">for</span> shape <span class="code-keyword">in</span> slide.shapes:</span>
<span class="code-line"> <span class="code-comment"># Extract text content</span></span>
<span class="code-line"> <span class="code-keyword">if</span> shape.has_text_frame:</span>
<span class="code-line"> <span class="code-keyword">if</span> shape <span class="code-operator">==</span> slide.shapes.title:</span>
<span class="code-line"> slide_data[<span class="code-string">"title"</span>] <span class="code-operator">=</span> shape.text</span>
<span class="code-line"> <span class="code-keyword">else</span>:</span>
<span class="code-line"> slide_data[<span class="code-string">"content"</span>].<span class="code-function">append</span>({<span class="code-string">"type"</span>: <span class="code-string">"text"</span>, <span class="code-string">"content"</span>: shape.text})</span>
<span class="code-line"></span>
<span class="code-line"> <span class="code-comment"># Extract images</span></span>
<span class="code-line"> <span class="code-keyword">if</span> shape.shape_type <span class="code-operator">==</span> <span class="code-number">13</span>: <span class="code-comment"># Picture type</span></span>
<span class="code-line"> image <span class="code-operator">=</span> shape.image</span>
<span class="code-line"> image_bytes <span class="code-operator">=</span> image.blob</span>
<span class="code-line"> image_ext <span class="code-operator">=</span> image.ext</span>
<span class="code-line"> image_name <span class="code-operator">=</span> <span class="code-string">f"slide{slide_num + 1}_img{len(slide_data['images']) + 1}.{image_ext}"</span></span>
<span class="code-line"> image_path <span class="code-operator">=</span> os.path.<span class="code-function">join</span>(assets_dir, image_name)</span>
<span class="code-line"> <span class="code-keyword">with</span> <span class="code-function">open</span>(image_path, <span class="code-string">"wb"</span>) <span class="code-keyword">as</span> f:</span>
<span class="code-line"> f.<span class="code-function">write</span>(image_bytes)</span></code></pre>
</div>
<div class="translation-english">
<span class="translation-label">大白话</span>
<div class="translation-lines">
<p class="tl">遍历这张幻灯片上的每一个 <span class="term" data-definition="在 PowerPoint 里,幻灯片上的任何对象——文本框、图片、箭头、矩形。你在幻灯片上看到的所有东西都是 shape。">shape</span>(对象),一次一个。</p>
<p class="tl"><strong>文字分支:</strong>如果这个对象有文字,而且它是幻灯片的标题,就存成标题。</p>
<p class="tl">否则就是正文——作为一个文本块加到 content 列表里。</p>
<p class="tl"><strong>图片分支:</strong>如果这个对象是图片(type 13 是 PowerPoint 里图片的代码)……</p>
<p class="tl">……就把图片取出来,拿到它的原始 <span class="term" data-definition="组成一个文件的原始 0 和 1——就像一张图片的单个像素数据,但适用于任何数字数据。">bytes</span>(真正的像素数据)和它的文件扩展名(.png、.jpg)。</p>
<p class="tl">给它起个唯一的名字,比如"slide3_img2.png",免得撞车。</p>
<p class="tl">拼出完整的保存路径,然后开一个新的二进制文件,把图片数据写进磁盘——这样新的 HTML 演示文稿就能在本地引用它,而不再依赖原始的 .pptx。</p>
</div>
</div>
</div>
<p>这是 <span class="term" data-definition="一种流行的编程语言,以接近英语、易读的语法著称——常用于脚本、数据处理和自动化。">Python</span> —— 选它干这活,是因为它自上而下读起来像英语,而且有能直接读懂 PowerPoint 文件的库。</p>
</section>
<!-- SCREEN 7: Callout — Separation of Concerns -->
<section class="screen animate-in">
<h2 class="screen-heading">为什么这很重要</h2>
<p>每个文件只管一件事,而且只管一件事。这不是巧合——这是整个仓库里最重要的想法:</p>
<div class="callout callout-accent">
<div class="callout-icon">💡</div>
<div class="callout-content">
<strong class="callout-title">关注点分离</strong>
<p>每个文件只干一件事,只干一件事。这就是为什么你能换服装(预设)却不动舞台吊装(<code>viewport-base.css</code>)。工程师管这叫 <span class="term" data-definition="一种设计原则:系统的每个部分只处理一件事,且只处理一件事——像一个厨房,厨师做菜、服务员上菜、收银员管钱,各管各的。">separation of concerns</span> ——它是你抓住 AI 把逻辑放错地方的超级能力。</p>
<p>如果你要换个字体,AI 却去改 <code>viewport-base.css</code>,你就知道这不对:字体归预设或选中的模板管,不归舞台管。<span class="term" data-definition="把系统的各部分设计成互不依赖——改一个不会弄坏别的。像乐高积木,能拼在一起,也能自由替换。">Decoupling</span> 让这种判断成为可能。</p>
</div>
</div>
</section>
<!-- SCREEN 8: Quiz -->
<section class="screen animate-in">
<h2 class="screen-heading">检验你的理解</h2>
<p>三个场景。想想每段逻辑住在哪儿——以及它什么时候被呼叫上场。</p>
<div class="quiz-container" id="quiz-module2">
<div class="quiz-question-block"
data-correct="option-b"
data-explanation-right="没错——selection-index.json 是发现入口。AI 先读它来找候选;这里没登记,你的新模板就形同隐形。"
data-explanation-wrong="不太对。想想 AI 是先读哪个文件来发现模板的。索引故意做得很小——它是 AI 在加载任何大文件之前先扫一遍的目录册。">
<h3 class="quiz-question">1. 你想新增第 35 套 bold 模板。哪个文件必须更新,AI 才能发现并把它列入候选?</h3>
<div class="quiz-options">
<button class="quiz-option" data-value="option-a" onclick="selectOption(this)">
<div class="quiz-option-radio"></div>
<span>design.md</span>
</button>
<button class="quiz-option" data-value="option-b" onclick="selectOption(this)">
<div class="quiz-option-radio"></div>
<span>selection-index.json</span>
</button>
<button class="quiz-option" data-value="option-c" onclick="selectOption(this)">
<div class="quiz-option-radio"></div>
<span>STYLE_PRESETS.md</span>
</button>
<button class="quiz-option" data-value="option-d" onclick="selectOption(this)">
<div class="quiz-option-radio"></div>
<span>viewport-base.css</span>
</button>
</div>
<div class="quiz-feedback"></div>
</div>
<div class="quiz-question-block"
data-correct="option-a"
data-explanation-right="没错——design.md 又大又详尽,所以 AI 只为用户选中的那一套模板加载它。把 34 套全读一遍会浪费 context,还会拖慢一切。"
data-explanation-wrong="不太对。关键在于 design.md 什么时候被读。它是这条链里最重的文件——AI 应该只在用户选定之后,为恰好一套模板加载它。">
<h3 class="quiz-question">2. AI 正在生成演示文稿,突然把全部 34 份 design.md 都读了一遍。它违反了哪条规则?</h3>
<div class="quiz-options">
<button class="quiz-option" data-value="option-a" onclick="selectOption(this)">
<div class="quiz-option-radio"></div>
<span>只为被选中的那一套模板读 design.md</span>
</button>
<button class="quiz-option" data-value="option-b" onclick="selectOption(this)">
<div class="quiz-option-radio"></div>
<span>改成读全部 preview.md</span>
</button>
<button class="quiz-option" data-value="option-c" onclick="selectOption(this)">
<div class="quiz-option-radio"></div>
<span>完全跳过 design.md</span>
</button>
<button class="quiz-option" data-value="option-d" onclick="selectOption(this)">
<div class="quiz-option-radio"></div>
<span>先读 STYLE_PRESETS.md</span>
</button>
</div>
<div class="quiz-feedback"></div>
</div>
<div class="quiz-question-block"
data-correct="option-c"
data-explanation-right="没错——extract-pptx.py 是第 4 阶段的转换器。它把文字、图片、备注从 .pptx 里抽出来,AI 才能把它们重建成 HTML 幻灯片。"
data-explanation-wrong="不太对。想想"转换"意味着什么——你得先把内容从 .pptx 里抽出来。这就是 extract-pptx.py 在第 4 阶段干的活。">
<h3 class="quiz-question">3. 你在转换一份 .pptx。AI 先跑哪个文件?</h3>
<div class="quiz-options">
<button class="quiz-option" data-value="option-a" onclick="selectOption(this)">
<div class="quiz-option-radio"></div>
<span>scripts/deploy.sh</span>
</button>
<button class="quiz-option" data-value="option-b" onclick="selectOption(this)">
<div class="quiz-option-radio"></div>
<span>scripts/export-pdf.sh</span>
</button>
<button class="quiz-option" data-value="option-c" onclick="selectOption(this)">
<div class="quiz-option-radio"></div>
<span>scripts/extract-pptx.py</span>
</button>
<button class="quiz-option" data-value="option-d" onclick="selectOption(this)">
<div class="quiz-option-radio"></div>
<span>viewport-base.css</span>
</button>
</div>
<div class="quiz-feedback"></div>
</div>
<button class="quiz-check-btn" onclick="checkQuiz('quiz-module2')">检查答案</button>
<button class="quiz-reset-btn" onclick="resetQuiz('quiz-module2')">重试</button>
</div>
</section>
<!-- SCREEN 9: Transition to Module 3 -->
<section class="screen animate-in">
<h2 class="screen-heading">接下来</h2>
<p>演员你都认识了。现在来看他们最聪明的那个招数:</p>
<div class="callout callout-info">
<div class="callout-icon">🔗</div>
<div class="callout-content">
<strong class="callout-title">模块 3 预告</strong>
<p>注意到 <code>selection-index.json</code>、<code>preview.md</code>、<code>design.md</code> 怎么串成一条链了吗?这条链是整个仓库最聪明的设计。下一模块我们深入讲 <span class="term" data-definition="一种设计模式:逐步释放信息——先给摘要,再按需给细节。像菜单,菜名一目了然摆在前,完整配料你要才给。">progressive disclosure</span> ——这条让 AI 的 <span class="term" data-definition="AI 一次能看见并记住的文本——它的工作记忆。AI 读的所有东西都会占这个预算,所以大文件很贵。">context</span> 保持精简的漏斗。</p>
</div>
</div>
</section>
</div>
</div>
</section>
<section class="module" id="module-3" style="background: var(--color-bg-warm)">
<div class="module-content">
<header class="module-header animate-in">
<span class="module-number">03</span>
<h1 class="module-title">渐进式披露</h1>
<p class="module-subtitle">34 个模板如何塞进 AI 的记忆里而不把它撑爆</p>
</header>
<div class="module-body">
<!-- Screen 1: The Memory Problem -->
<section class="screen animate-in">
<h2 class="screen-heading">34 本手册,一个问题</h2>
<p>一共有 34 个 bold 模板,每个都配了一本完整的设计手册。如果 AI 每次给你做演示文稿时都把 34 本手册全读一遍,它还没写出一页幻灯片就会把 <span class="term" data-definition="AI 一次能记住的文本量——它的工作记忆。输入太多,早先的细节就会被挤出去,就像一张放不下所有资料的桌子。">context window</span> 撑爆——更糟的是,它还可能从错的模板里 <span class="term" data-definition="AI 一本正经地编造不存在的东西——比如凭空捏造一个不存在的模板。通常是信息太多或对的信息太少时发生。">hallucinate</span> 出一些细节。</p>
<p>这个仓库用一个 <span class="term" data-definition="分阶段展示信息——先给一个极小的摘要,等选择范围缩小了再展示更多。像逛博物馆:先看楼层图,再看展品牌,最后才走进展厅。">progressive disclosure</span> 漏斗来解决这个问题:一份列出全部 34 个模板的极小 <span class="term" data-definition="一个紧凑的目录,列出每一项的几个关键信息——就像书后的索引,而不是正文章节。">index</span>,一份候选 <span class="term" data-definition="从一大堆里挑出的一小拨——就像海选后留下的 3 个决赛选手。">shortlist</span> 的预览,最后才是恰好一份完整的 <span class="term" data-definition="在这个代码库里指 design.md 文件——单个模板的完整搭建说明。就像一份菜谱:每种配料、每个步骤都摆得明明白白。">recipe</span>。</p>
<p>想象你去逛博物馆。你永远不会把每块展品牌都读完,也不会把所有墙面文字一次性全扛在身上:</p>
<div class="icon-rows">
<div class="icon-row">
<div class="icon-circle" style="background: var(--color-actor-3)">🗺️</div>
<div>
<strong>楼层图 —— selection-index.json</strong>
<p>入口处的一张小地图。标出每个展品在哪里,每个带几个标签。你把 34 个全扫一遍——但什么都不深入读。</p>
</div>
</div>
<div class="icon-row">
<div class="icon-circle" style="background: var(--color-actor-2)">🏷️</div>
<div>
<strong>展品牌 —— preview.md</strong>
<p>每个展厅门口的一张卡片。扫一眼就知道里面有什么。你读 3 到 4 张——绝不是 34 张全读。</p>
</div>
</div>
<div class="icon-row">
<div class="icon-circle" style="background: var(--color-actor-5)">📖</div>
<div>
<strong>墙面说明 —— design.md</strong>
<p>完整的介绍文字,只挂在你真正走进的那一个展厅里。内容齐全,但你一次只看一份。</p>
</div>
</div>
</div>
</section>
<!-- Screen 2: The Funnel Animation -->
<section class="screen animate-in">
<h2 class="screen-heading">看漏斗如何收窄</h2>
<p>三个文件,三个阶段。点着往下走,看 AI 如何越读越少——但越读越深。</p>
<div class="flow-animation" data-steps='[
{"highlight":"flow-actor-1","label":"从这里开始:34 个模板,但只有 metadata——情绪、正式度、配色方案。文件很小。"},
{"highlight":"flow-actor-1","label":"AI 拿你的需求跟 metadata 比对,挑出 3 个候选。","packet":true,"from":"actor-1","to":"actor-2"},
{"highlight":"flow-actor-2","label":"只读取这 3 张 preview.md 卡片。每张扫一眼——足够渲染一页标题幻灯片。"},
{"highlight":"flow-actor-2","label":"你看着预览,从中选一个。","packet":true,"from":"actor-2","to":"actor-3"},
{"highlight":"flow-actor-3","label":"这时 AI 才加载那一份 design.md——完整菜谱。34 本手册摆在那里,从头到尾只读了 1 本。"}
]'>
<div class="flow-actors">
<div class="flow-actor" id="flow-actor-1">
<div class="flow-actor-icon" style="background: var(--color-actor-3)">34</div>
<span>Index —— 34 个模板</span>
</div>
<div class="flow-actor" id="flow-actor-2">
<div class="flow-actor-icon" style="background: var(--color-actor-2)">3</div>
<span>Preview —— 3 张卡片</span>
</div>
<div class="flow-actor" id="flow-actor-3">
<div class="flow-actor-icon" style="background: var(--color-actor-5)">1</div>
<span>Design.md —— 1 份菜谱</span>
</div>
</div>
<div class="flow-packet" id="flow-packet"></div>
<div class="flow-step-label" id="flow-label">点击「下一步」开始</div>
<div class="flow-controls">
<button class="btn flow-next-btn">下一步</button>
<button class="btn flow-reset-btn">重新开始</button>
<span class="flow-progress"></span>
</div>
</div>
</section>
<!-- Screen 3: The Self-Documenting Contract -->
<section class="screen animate-in">
<h2 class="screen-heading">文件自己声明自己的规矩</h2>
<p>index 文件不只是列模板——它还带了一段 <span class="term" data-definition="一种用花括号和引号把数据写成文本的格式,人和机器都能读。就像一张填得整整齐齐的资料卡。">JSON</span>,明确告诉 AI 该怎么用它。每个键都是一道关卡规则:</p>
<div class="translation-block animate-in">
<div class="translation-code">
<span class="translation-label">CODE</span>
<pre><code><span class="code-line"><span class="code-property">"usage"</span>: {</span>
<span class="code-line"> <span class="code-property">"selection"</span>: <span class="code-string">"Read this compact index first to shortlist bold templates from metadata."</span>,</span>
<span class="code-line"> <span class="code-property">"previews"</span>: <span class="code-string">"For title-slide previews, read only the preview_md files for the shortlisted bold candidates."</span>,</span>
<span class="code-line"> <span class="code-property">"final_generation"</span>: <span class="code-string">"After the user chooses a bold template, read exactly that template design_md before generating the full deck."</span>,</span>
<span class="code-line"> <span class="code-property">"never"</span>: <span class="code-string">"Do not bulk-read templates/*/design.md and do not read template.html unless the selected design.md is missing a critical implementation detail."</span></span>
<span class="code-line">}</span>
</code></pre>
</div>
<div class="translation-english">
<span class="translation-label">大白话</span>
<div class="translation-lines">
<p class="tl">这段是一份契约。文件自己告诉 AI 该怎么用它——不用猜。</p>
<p class="tl"><strong>selection:</strong> 阶段一。永远先读这份小 index。用它挑出几个候选。</p>
<p class="tl"><strong>previews:</strong> 阶段二。只有这时才读 preview 卡片——而且只读你挑中的那些候选。</p>
<p class="tl"><strong>final_generation:</strong> 阶段三。用户选定一个之后,就读那一份 design.md。</p>
<p class="tl"><strong>never:</strong> 禁区。绝不一次打开全部 34 份 design.md。那会把记忆预算撑爆。</p>
</div>
</div>
</div>
<div class="callout callout-info">