1实现原理 · 为什么它能做到
整份模板的核心假设是「outline 是真理, skill 是渲染器」:铁律禁止改动任何文字与顺序,唯一被允许的动作是把过长的段落做物理分页。这直接消灭了「AI 抽提 + 重写」最常见的信息损耗。
- 标题不改字, 段落不改字, 列表不改字, 顺序不重排
markdown 元素到页型是一张一对一映射表:一级标题→emphasis 封面页、二级标题→独占 theme 页、段落按字数分档、列表按项数拆页、--- →纯色休止页、**强调** → hl 高亮。
| `# 一级标题` | 独占 **emphasis** 封面页(accent 底色, 通常单字/单短词) |
主题色由文档调性推断且一篇只允许一个:默认 black(沉思/论证)、宣言类 red、反讽批判类 yellow;每个主题同时还绑定了默认页底色、emphasis 页底色与 hl 色。
| 沉思 / 论证 / 笔记(默认) | **black** | 黑底白字 | 红底白字 | 红 `#E63956` |
字号不是手选的,而是运行时算出来的:SKILL.md 给出 CJK 按 1.8 计权的档位表,骨架 JS 里的 lengthTier() 用「最长行字符数 +(行数-1)×4」选 clamp 档位。示例对 8 页分别算出 single/short/medium/long。
| single | ≤2 | `clamp(320px, 80vmin, 1100px)` |
SKILL.md 直接内嵌了完整可运行的 HTML 骨架(内联 CSS + JS),并明令复用不要改、只填 SLIDES / title / subtitle / data-theme;示例文件就是填好的产物。
完整 HTML 骨架(agent 应**复用 CSS 与 JS 不要改**, 只填 SLIDES / title / subtitle / data-theme):
骨架自带完整交互:键盘(→/←/space/Enter/j/k/PageUp/PageDown/Home/End/F 全屏)、触摸滑动(±40px 阈值)、点击左右半屏翻页,且用 escapeHtml() 转义所有注入 SLIDES 的文本。
return c.hl ? '<span class="hl">' + t + '</span>' : t;
示例是「同一份 outline 的忠实渲染」:example.md 给出 8 段 AI 演讲大纲(含一个 --- 分隔符),example.html 的 SLIDES 恰为 8 项——首项 emphasis 单字「AI」对应 # AI,分隔符对应空 emphasis 休止页,末页是收束反问。
{ emphasis: true, lines: [] },
唯一明令禁止外部资源:骨架不含任何 CDN / 字体外链,字体栈走系统(Helvetica Neue / Arial Black / PingFang SC),因此产物可离线双击打开。
**不要外链 CDN, 不要外部资源**。
2核心能力
3外部依赖
| 类型 | 依赖 |
|---|---|
| package | 无外部依赖:字体走系统栈(Helvetica Neue / Arial Black / PingFang SC),骨架不引任何 CDN |
| network | 宿主共享指令声明的 Tailwind CDN(宿主侧默认,本模板显式禁止使用) |
| network | 第三方 skill 来源标注(frontmatter example_source_url,仅作出处记录,非运行时调用) |
4风险提醒 风险提醒:绿色 · 放心使用
- 宿主侧:预览 iframe 放宽沙箱 — template-picker.tsx 用 srcDoc + sandbox="allow-scripts allow-same-origin";本模板产物含 JS,预览时脚本会真实执行(自身只操作 DOM),但沙箱放宽属宿主实现风险,不判档。
- 宿主侧:会 spawn 本地 agent CLI — convert 路由经 invokeAgent 以本地已登录 CLI 执行 prompt。
- 表现力受「不许改动」限制 — 原文不能改写、不能用图片图标,若用户的大纲本身冗长或口语化,铸出来的巨字页会难看;模板不会替你润色。
- 极端字号在小屏会溢出 — single 档为 clamp(320px, 80vmin, 1100px) 且 .line 为 white-space:nowrap,窄屏 / 投影比例异常时依赖 vmin 收缩,仍可能出现横向裁切。
5第二遍独立确认
- [ok] 「1:1 铸页」是否在示例中真实成立 — example.md 的结构(# AI / ## 两个二级标题 / 两个列表 / --- / ## 收束问句)与 example.html 的 8 项 SLIDES 逐项对应:首项 emphasis 单字 AI、列表项按 indent:1 渲染、--- 变成空 lines 的 emphasis 休止页、末页 emphasis 收束。
- [ok] 字号档位是否由代码而非人工决定 — lengthTier() 以「最长行字符数 +(行数-1)×4」判断档位,lineCharLen() 对 CJK 字符计权 1.8,与 SKILL.md 的档位表一致。
- [ok] 「不要外链 CDN」是否被示例遵守 — example.html 与 SKILL.md 各自的 http(s):// 计数均为 0;SKILL.md 内有 2 处 github.com 链接(frontmatter example_source_url 与正文致谢的上游 ljg-skills 出处),属第三方来源标注而非运行时资源。内嵌骨架本身不含任何 CDN / 字体外链,字体走系统栈,产物可离线双击打开。
- [ok] 注入面:SLIDES 文本是否被转义 — escapeHtml() 对 & < > " ' 做实体转义,再拼进 innerHTML;SLIDES 内容来自用户大纲,属必要防护。
- [discrepancy] example.html 的 <script> 是否属模板自带可执行代码 — 是(本批 deck 示例里唯一有 1 个 <script> 的目录)。该脚本是 SKILL.md 内嵌骨架的一部分(翻页交互 + 字号分档),只会操作 DOM 与读取键盘/触摸事件,无网络请求、无存储、无凭证访问;展示层按「模板自带脚本」理解即可,不影响判档(仍为 green:无外发、无写盘)。
- [ok] pin commit 与路径 — HEAD = 553ed98c283f9c0f489902d035416a972d6a9699;skill.path = next/src/lib/templates/skills/deck-ljg-present,含 SKILL.md。
- [discrepancy] README 收录一致性 — README 的 deck 表列出 20 个 deck-* 模板,但没有 deck-ljg-present(该 pin 下 deck-* 实为 21 个)。文档滞后,不影响模板行为。
6结论
d549ea071c2237ec…553ed98c28