【模板: 宣言式演讲(Outline-Faithful)】
【意图】把用户的 outline / markdown 1:1 视觉化为色块大字 manifesto deck。不抽提、不重写、不重排、不浓缩——只决定每一行/每一节渲染为哪一页。审美参考:Felipe Franco / BIG STUDIOS 的 manifesto 大字海报。
【铁律 — 全部违反必须重做】
- 标题不改字, 段落不改字, 列表不改字, 顺序不重排
- 唯一允许的"动"是物理分页(一段太长拆成多页)
- 不抽 manifesto / 不写新句子 / 不删内容 / 不放图片图标 / 不用过渡动画
- 一篇只用一个主题色(black / red / yellow 三选一)
【outline → 页面映射】
| 输入元素 |
输出页 |
# 一级标题 |
独占 emphasis 封面页(accent 底色, 通常单字/单短词) |
## 二级标题 |
独占 theme 页(大字标题独占一页) |
### 三级标题+ |
独占 theme 页(字号自动降一档) |
| 段落(≤30字) |
单 theme 页 |
| 段落(30-80字, 多句号) |
每句一页(medium 档) |
| 段落(>80字) |
按 ~30 字一页拆, 末尾加 ⋯ |
- 列表项(≤4) |
一页全展示, indent 按嵌套深度 0/1/2 |
| 列表 5-8 项 |
拆 2 页, 每页 3-4 项, 项数接近 |
| 列表 >8 项 |
拆多页, 每页 4 项 |
| 表格 ≤6 行 |
单页 |
| 表格 >6 行 |
拆多页, 每页保留表头 |
**强调** / `code` |
自动 hl: true |
--- 分隔符 |
独立 emphasis 休止页(空 emphasis, 纯色块) |
首末页自动 emphasis:文档首段(如已是 # 则合并)+ 文档末段 = emphasis 开场 / 收束页。一级标题就是天然的章节断点, 不要为了凑节奏强行加 emphasis。
【主题色推断 — 一篇只能一个】
| 文档调性 / 标签 |
theme |
默认页 |
emphasis 页 |
hl 色(仅 theme 页生效) |
| 沉思 / 论证 / 笔记(默认) |
black |
黑底白字 |
红底白字 |
红 #E63956 |
宣言 / 号召 / 演讲(含 share / manifesto / keynote / talk 标签或语气) |
red |
红底白字 |
黑底白字 |
柔金黄 #FFE082 |
反讽 / 警觉 / 批判(含 critique / warn / rant) |
yellow |
黄底黑字 |
黑底白字 |
红 #E63956 |
显式覆盖:用户写"用 red / 用 yellow / 用黑底"即按指令。无任何线索时默认 black。
【视觉规范 — 数值锁死】
色板(仅 4 色, 不许改 hex):
--c-black: #1A1A1A
--c-red: #E63956
--c-yellow: #FFD400
--c-white: #FFFFFF
--c-gold: #FFE082
字体栈(必须用 ultra-bold 900, letter-spacing -0.05em):
"Helvetica Neue", "Arial Black", "Inter", "PingFang SC", "Heiti SC", "STHeiti", -apple-system, sans-serif
font-weight: 900
字号档位(按本页最长那一行字符数, CJK 按 1.8 计权, 多行页降一档):
| 档位 |
字符数 |
font-size |
| single |
≤2 |
clamp(320px, 80vmin, 1100px) |
| short |
3-6 |
clamp(240px, 55vmin, 780px) |
| medium |
7-14 |
clamp(150px, 35vmin, 480px) |
| long |
15-26 |
clamp(100px, 22vmin, 320px) |
| xlong |
27+ |
clamp(64px, 14vmin, 200px) |
排版:
- padding
6vmin 7vmin, 让大字撑满边缘
.lines 块在屏幕内水平居中, 但块内每行 left-aligned(消除右侧空白同时保 indent 错位)
- line-height
1.05, 行间 gap 0.15em
- 内容垂直居中
- 页脚:左下页码(
01 / 08)+ 右下副标题, 13px monospace, opacity 0.5, uppercase, letter-spacing 0.12em
- emphasis 页:背景换
--acc-bg, 字色换 --acc-fg, 行内 .hl 自动 color: inherit(emphasis 整页就是高亮)
- indent 档位:0 =
0, 1 = 7vmin, 2 = 16vmin
【输出契约】
输出单文件 HTML, 完全自包含, inline CSS + inline JS, 直接在 iframe sandbox 里能跑。骨架照下面这个模板, 把 SLIDES 数组、<title>、{{SUBTITLE}}、body[data-theme] 填好即可。不要外链 CDN, 不要外部资源。
SLIDES 数组每项形态:
// 默认 theme 页
{ lines: [ { indent: 0, chunks: [ {t: "前段"}, {t: "高亮词", hl: true}, {t: "后段"} ] } ] }
// emphasis 页(accent 底色, inline hl 自动忽略)
{ emphasis: true, lines: [ { indent: 0, chunks: [ {t: "AI"} ] } ] }
// 休止页 = emphasis + 空 lines
{ emphasis: true, lines: [] }
完整 HTML 骨架(agent 应复用 CSS 与 JS 不要改, 只填 SLIDES / title / subtitle / data-theme):
<!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>
:root {
--c-black: #1A1A1A; --c-red: #E63956; --c-yellow: #FFD400;
--c-white: #FFFFFF; --c-gold: #FFE082;
}
* { margin: 0; padding: 0; box-sizing: border-box; }
html, body {
width: 100%; height: 100%;
font-family: "Helvetica Neue", "Arial Black", "Inter", "PingFang SC", "Heiti SC", "STHeiti", -apple-system, sans-serif;
font-weight: 900; overflow: hidden;
-webkit-font-smoothing: antialiased;
letter-spacing: -0.05em;
}
body[data-theme="black"] { --bg: var(--c-black); --fg: var(--c-white); --acc-bg: var(--c-red); --acc-fg: var(--c-white); --hl: var(--c-red); }
body[data-theme="red"] { --bg: var(--c-red); --fg: var(--c-white); --acc-bg: var(--c-black); --acc-fg: var(--c-white); --hl: var(--c-gold); }
body[data-theme="yellow"] { --bg: var(--c-yellow); --fg: var(--c-black); --acc-bg: var(--c-black); --acc-fg: var(--c-white); --hl: var(--c-red); }
body { background: var(--bg); }
.stage { position: fixed; inset: 0; }
.slide {
position: absolute; inset: 0; display: none;
flex-direction: column; justify-content: center; align-items: center;
padding: 6vmin 7vmin;
background: var(--bg); color: var(--fg);
}
.slide.active { display: flex; }
.slide[data-emphasis="true"] { background: var(--acc-bg); color: var(--acc-fg); }
.slide .hl { color: var(--hl); }
.slide[data-emphasis="true"] .hl { color: inherit; }
.lines { display: flex; flex-direction: column; gap: 0.15em; line-height: 1.05; max-width: 100%; align-items: flex-start; }
.line { white-space: nowrap; text-align: left; }
.line[data-indent="0"] { padding-left: 0; }
.line[data-indent="1"] { padding-left: 7vmin; }
.line[data-indent="2"] { padding-left: 16vmin; }
.slide[data-len="single"] .lines { font-size: clamp(320px, 80vmin, 1100px); }
.slide[data-len="short"] .lines { font-size: clamp(240px, 55vmin, 780px); }
.slide[data-len="medium"] .lines { font-size: clamp(150px, 35vmin, 480px); }
.slide[data-len="long"] .lines { font-size: clamp(100px, 22vmin, 320px); }
.slide[data-len="xlong"] .lines { font-size: clamp(64px, 14vmin, 200px); }
.pager, .subtitle {
position: fixed; bottom: 2.5vmin;
font-family: "Menlo", "Monaco", monospace;
font-size: 13px; font-weight: 400; letter-spacing: 0.12em;
user-select: none; z-index: 10; text-transform: uppercase;
opacity: 0.5; color: var(--fg);
}
.pager { left: 3vmin; }
.subtitle { right: 3vmin; }
body[data-current="emphasis"] .pager,
body[data-current="emphasis"] .subtitle { color: var(--acc-fg); }
</style>
</head>
<body data-theme="red"><!-- black|red|yellow -->
<div class="stage" id="stage"></div>
<div class="pager" id="pager">01 / 01</div>
<div class="subtitle" id="subtitle"><!-- 副标题 / 品牌, 可空 --></div>
<script>
const SLIDES = [ /* 填入按 outline 映射出的 slides 数组 */ ];
const stage = document.getElementById('stage');
const pager = document.getElementById('pager');
const body = document.body;
function lineCharLen(chunks) {
const CJK = /[ -〿㐀-䶿一-鿿豈--]/;
return chunks.reduce((acc, c) => {
let len = 0;
for (const ch of (c.t || '')) len += CJK.test(ch) ? 1.8 : 1;
return acc + len;
}, 0);
}
function maxLineLen(lines) { return lines && lines.length ? Math.max(...lines.map(l => lineCharLen(l.chunks || []))) : 0; }
function lengthTier(maxLen, lineCount) {
const adj = maxLen + Math.max(0, lineCount - 1) * 4;
if (adj <= 2) return 'single';
if (adj <= 6) return 'short';
if (adj <= 14) return 'medium';
if (adj <= 26) return 'long';
return 'xlong';
}
function escapeHtml(s) {
return String(s == null ? '' : s)
.replace(/&/g, '&').replace(/</g, '<')
.replace(/>/g, '>').replace(/"/g, '"').replace(/'/g, ''');
}
SLIDES.forEach((s) => {
const el = document.createElement('div');
el.className = 'slide';
if (s.emphasis) el.setAttribute('data-emphasis', 'true');
if (s.lines && s.lines.length) {
el.setAttribute('data-len', lengthTier(maxLineLen(s.lines), s.lines.length));
const linesEl = document.createElement('div');
linesEl.className = 'lines';
s.lines.forEach(line => {
const lineEl = document.createElement('div');
lineEl.className = 'line';
lineEl.setAttribute('data-indent', String(line.indent || 0));
lineEl.innerHTML = (line.chunks || []).map(c => {
const t = escapeHtml(c.t);
return c.hl ? '<span class="hl">' + t + '</span>' : t;
}).join('');
linesEl.appendChild(lineEl);
});
el.appendChild(linesEl);
}
stage.appendChild(el);
});
const slides = stage.querySelectorAll('.slide');
let idx = 0;
function show(i) {
if (i < 0) i = 0; if (i >= slides.length) i = slides.length - 1;
slides[idx].classList.remove('active');
idx = i;
slides[idx].classList.add('active');
pager.textContent = String(idx + 1).padStart(2, '0') + ' / ' + String(slides.length).padStart(2, '0');
body.setAttribute('data-current', slides[idx].getAttribute('data-emphasis') === 'true' ? 'emphasis' : 'theme');
}
function next() { show(idx + 1); }
function prev() { show(idx - 1); }
document.addEventListener('keydown', (e) => {
switch (e.key) {
case 'ArrowRight': case ' ': case 'Enter': case 'j': case 'PageDown': e.preventDefault(); next(); break;
case 'ArrowLeft': case 'k': case 'PageUp': e.preventDefault(); prev(); break;
case 'Home': e.preventDefault(); show(0); break;
case 'End': e.preventDefault(); show(slides.length - 1); break;
case 'f': case 'F': e.preventDefault(); document.fullscreenElement ? document.exitFullscreen?.() : document.documentElement.requestFullscreen?.(); break;
}
});
let touchX = null;
document.addEventListener('touchstart', (e) => { touchX = e.touches[0].clientX; });
document.addEventListener('touchend', (e) => {
if (touchX == null) return;
const dx = e.changedTouches[0].clientX - touchX;
if (dx < -40) next(); else if (dx > 40) prev();
touchX = null;
});
document.addEventListener('click', (e) => {
if (e.target.closest('.pager,.subtitle')) return;
const mid = window.innerWidth / 2;
if (e.clientX > mid) next(); else prev();
});
show(0);
</script>
</body>
</html>
【调用流程 — agent 内部】
- 读用户内容(markdown / outline / 纯文本)
- 按上面表格做 outline → slides 数组 映射, 不抽提不重写
- 推断 theme(标签 > 语气 > 默认 black)
- 复用骨架, 替换
<title> / data-theme / <div id="subtitle"> 内容 / SLIDES 数组
- 一次性输出整个 HTML 文档
【品味准则】
- outline 是真理, skill 是渲染器
- 一级标题 = emphasis 封面(天然章节断点)
- 二级标题 = 独占 theme 页(给标题应有的重量)
- 列表错位靠 indent 0/1/2 体现嵌套深度
**强调** 自动 hl
- 拆页保持视觉一致性(同源块字号/缩进对齐)
- 左对齐不居中——这是 manifesto 美学的灵魂
【禁区】
- 不抽 manifesto(不要"找钉子", 作者已经写好了 outline)
- 不写新句子、不重组顺序、不删内容
- 不放图片 / 不放图标 / 不加过渡动画
- 不在 emphasis 页用 inline hl(emphasis 整页就是高亮)
- 不混用多个 theme(一篇一个气质)
- 不擅自加 emphasis(只有一级标题 / 首末页 / 分隔符)
【致谢】
本 skill 改编自 lijigang/ljg-skills · ljg-present(v3.0.0)。原版输出多主题包含 cyber-hacker 模式与 PNG 投影; html-anything 版只保留 3 主题 + 单文件 HTML 输出。审美灵感继续指向 Felipe Franco / BIG STUDIOS 的 manifesto 字体海报。
1---2name: deck-ljg-present3description: Visualizes outlines and markdown as bold, color-block manifesto-style decks without rewriting or reordering content. Supports black, red, and yellow themes.4---56【模板: 宣言式演讲(Outline-Faithful)】78【意图】把用户的 outline / markdown 1:1 视觉化为色块大字 manifesto deck。**不抽提、不重写、不重排、不浓缩**——只决定每一行/每一节渲染为哪一页。审美参考:Felipe Franco / BIG STUDIOS 的 manifesto 大字海报。910【铁律 — 全部违反必须重做】11- 标题不改字, 段落不改字, 列表不改字, 顺序不重排12- 唯一允许的"动"是**物理分页**(一段太长拆成多页)13- 不抽 manifesto / 不写新句子 / 不删内容 / 不放图片图标 / 不用过渡动画14- 一篇只用一个主题色(black / red / yellow 三选一)1516【outline → 页面映射】1718| 输入元素 | 输出页 |19|---|---|20| `# 一级标题` | 独占 **emphasis** 封面页(accent 底色, 通常单字/单短词) |21| `## 二级标题` | 独占 **theme** 页(大字标题独占一页) |22| `### 三级标题`+ | 独占 theme 页(字号自动降一档) |23| 段落(≤30字) | 单 theme 页 |24| 段落(30-80字, 多句号) | 每句一页(medium 档) |25| 段落(>80字) | 按 ~30 字一页拆, 末尾加 `⋯` |26| `- 列表项`(≤4) | 一页全展示, indent 按嵌套深度 0/1/2 |27| 列表 5-8 项 | 拆 2 页, 每页 3-4 项, 项数接近 |28| 列表 >8 项 | 拆多页, 每页 4 项 |29| 表格 ≤6 行 | 单页 |30| 表格 >6 行 | 拆多页, 每页保留表头 |31| `**强调**` / `` `code` `` | 自动 `hl: true` |32| `---` 分隔符 | 独立 **emphasis 休止页**(空 emphasis, 纯色块) |3334**首末页自动 emphasis**:文档首段(如已是 `#` 则合并)+ 文档末段 = emphasis 开场 / 收束页。一级标题就是天然的章节断点, 不要为了凑节奏强行加 emphasis。3536【主题色推断 — 一篇只能一个】3738| 文档调性 / 标签 | theme | 默认页 | emphasis 页 | hl 色(仅 theme 页生效) |39|---|---|---|---|---|40| 沉思 / 论证 / 笔记(默认) | **black** | 黑底白字 | 红底白字 | 红 `#E63956` |41| 宣言 / 号召 / 演讲(含 `share` / `manifesto` / `keynote` / `talk` 标签或语气) | **red** | 红底白字 | 黑底白字 | 柔金黄 `#FFE082` |42| 反讽 / 警觉 / 批判(含 `critique` / `warn` / `rant`) | **yellow** | 黄底黑字 | 黑底白字 | 红 `#E63956` |4344显式覆盖:用户写"用 red / 用 yellow / 用黑底"即按指令。无任何线索时默认 black。4546【视觉规范 — 数值锁死】4748色板(仅 4 色, 不许改 hex):49```50--c-black: #1A1A1A51--c-red: #E6395652--c-yellow: #FFD40053--c-white: #FFFFFF54--c-gold: #FFE08255```5657字体栈(必须用 ultra-bold 900, letter-spacing `-0.05em`):58```59"Helvetica Neue", "Arial Black", "Inter", "PingFang SC", "Heiti SC", "STHeiti", -apple-system, sans-serif60font-weight: 90061```6263字号档位(按本页**最长那一行**字符数, CJK 按 1.8 计权, 多行页降一档):6465| 档位 | 字符数 | font-size |66|---|---|---|67| single | ≤2 | `clamp(320px, 80vmin, 1100px)` |68| short | 3-6 | `clamp(240px, 55vmin, 780px)` |69| medium | 7-14 | `clamp(150px, 35vmin, 480px)` |70| long | 15-26 | `clamp(100px, 22vmin, 320px)` |71| xlong | 27+ | `clamp(64px, 14vmin, 200px)` |7273排版:74- padding `6vmin 7vmin`, 让大字撑满边缘75- `.lines` 块在屏幕内水平居中, 但块内每行 **left-aligned**(消除右侧空白同时保 indent 错位)76- line-height `1.05`, 行间 gap `0.15em`77- 内容垂直居中78- 页脚:左下页码(`01 / 08`)+ 右下副标题, 13px monospace, opacity 0.5, uppercase, letter-spacing `0.12em`79- emphasis 页:背景换 `--acc-bg`, 字色换 `--acc-fg`, 行内 `.hl` 自动 `color: inherit`(emphasis 整页就是高亮)80- indent 档位:0 = `0`, 1 = `7vmin`, 2 = `16vmin`8182【输出契约】8384输出**单文件 HTML**, 完全自包含, inline CSS + inline JS, 直接在 iframe sandbox 里能跑。骨架照下面这个模板, 把 `SLIDES` 数组、`<title>`、`{{SUBTITLE}}`、`body[data-theme]` 填好即可。**不要外链 CDN, 不要外部资源**。8586SLIDES 数组每项形态:87```js88// 默认 theme 页89{ lines: [ { indent: 0, chunks: [ {t: "前段"}, {t: "高亮词", hl: true}, {t: "后段"} ] } ] }90// emphasis 页(accent 底色, inline hl 自动忽略)91{ emphasis: true, lines: [ { indent: 0, chunks: [ {t: "AI"} ] } ] }92// 休止页 = emphasis + 空 lines93{ emphasis: true, lines: [] }94```9596完整 HTML 骨架(agent 应**复用 CSS 与 JS 不要改**, 只填 SLIDES / title / subtitle / data-theme):9798```html99<!DOCTYPE html>100<html lang="zh-CN">101<head>102<meta charset="UTF-8">103<meta name="viewport" content="width=device-width, initial-scale=1.0">104<title><!-- 文档标题 --></title>105<style>106 :root {107 --c-black: #1A1A1A; --c-red: #E63956; --c-yellow: #FFD400;108 --c-white: #FFFFFF; --c-gold: #FFE082;109 }110 * { margin: 0; padding: 0; box-sizing: border-box; }111 html, body {112 width: 100%; height: 100%;113 font-family: "Helvetica Neue", "Arial Black", "Inter", "PingFang SC", "Heiti SC", "STHeiti", -apple-system, sans-serif;114 font-weight: 900; overflow: hidden;115 -webkit-font-smoothing: antialiased;116 letter-spacing: -0.05em;117 }118 body[data-theme="black"] { --bg: var(--c-black); --fg: var(--c-white); --acc-bg: var(--c-red); --acc-fg: var(--c-white); --hl: var(--c-red); }119 body[data-theme="red"] { --bg: var(--c-red); --fg: var(--c-white); --acc-bg: var(--c-black); --acc-fg: var(--c-white); --hl: var(--c-gold); }120 body[data-theme="yellow"] { --bg: var(--c-yellow); --fg: var(--c-black); --acc-bg: var(--c-black); --acc-fg: var(--c-white); --hl: var(--c-red); }121 body { background: var(--bg); }122 .stage { position: fixed; inset: 0; }123 .slide {124 position: absolute; inset: 0; display: none;125 flex-direction: column; justify-content: center; align-items: center;126 padding: 6vmin 7vmin;127 background: var(--bg); color: var(--fg);128 }129 .slide.active { display: flex; }130 .slide[data-emphasis="true"] { background: var(--acc-bg); color: var(--acc-fg); }131 .slide .hl { color: var(--hl); }132 .slide[data-emphasis="true"] .hl { color: inherit; }133 .lines { display: flex; flex-direction: column; gap: 0.15em; line-height: 1.05; max-width: 100%; align-items: flex-start; }134 .line { white-space: nowrap; text-align: left; }135 .line[data-indent="0"] { padding-left: 0; }136 .line[data-indent="1"] { padding-left: 7vmin; }137 .line[data-indent="2"] { padding-left: 16vmin; }138 .slide[data-len="single"] .lines { font-size: clamp(320px, 80vmin, 1100px); }139 .slide[data-len="short"] .lines { font-size: clamp(240px, 55vmin, 780px); }140 .slide[data-len="medium"] .lines { font-size: clamp(150px, 35vmin, 480px); }141 .slide[data-len="long"] .lines { font-size: clamp(100px, 22vmin, 320px); }142 .slide[data-len="xlong"] .lines { font-size: clamp(64px, 14vmin, 200px); }143 .pager, .subtitle {144 position: fixed; bottom: 2.5vmin;145 font-family: "Menlo", "Monaco", monospace;146 font-size: 13px; font-weight: 400; letter-spacing: 0.12em;147 user-select: none; z-index: 10; text-transform: uppercase;148 opacity: 0.5; color: var(--fg);149 }150 .pager { left: 3vmin; }151 .subtitle { right: 3vmin; }152 body[data-current="emphasis"] .pager,153 body[data-current="emphasis"] .subtitle { color: var(--acc-fg); }154</style>155</head>156<body data-theme="red"><!-- black|red|yellow -->157<div class="stage" id="stage"></div>158<div class="pager" id="pager">01 / 01</div>159<div class="subtitle" id="subtitle"><!-- 副标题 / 品牌, 可空 --></div>160<script>161 const SLIDES = [ /* 填入按 outline 映射出的 slides 数组 */ ];162 const stage = document.getElementById('stage');163 const pager = document.getElementById('pager');164 const body = document.body;165 function lineCharLen(chunks) {166 const CJK = /[ -〿㐀-䶿一-鿿豈--]/;167 return chunks.reduce((acc, c) => {168 let len = 0;169 for (const ch of (c.t || '')) len += CJK.test(ch) ? 1.8 : 1;170 return acc + len;171 }, 0);172 }173 function maxLineLen(lines) { return lines && lines.length ? Math.max(...lines.map(l => lineCharLen(l.chunks || []))) : 0; }174 function lengthTier(maxLen, lineCount) {175 const adj = maxLen + Math.max(0, lineCount - 1) * 4;176 if (adj <= 2) return 'single';177 if (adj <= 6) return 'short';178 if (adj <= 14) return 'medium';179 if (adj <= 26) return 'long';180 return 'xlong';181 }182 function escapeHtml(s) {183 return String(s == null ? '' : s)184 .replace(/&/g, '&').replace(/</g, '<')185 .replace(/>/g, '>').replace(/"/g, '"').replace(/'/g, ''');186 }187 SLIDES.forEach((s) => {188 const el = document.createElement('div');189 el.className = 'slide';190 if (s.emphasis) el.setAttribute('data-emphasis', 'true');191 if (s.lines && s.lines.length) {192 el.setAttribute('data-len', lengthTier(maxLineLen(s.lines), s.lines.length));193 const linesEl = document.createElement('div');194 linesEl.className = 'lines';195 s.lines.forEach(line => {196 const lineEl = document.createElement('div');197 lineEl.className = 'line';198 lineEl.setAttribute('data-indent', String(line.indent || 0));199 lineEl.innerHTML = (line.chunks || []).map(c => {200 const t = escapeHtml(c.t);201 return c.hl ? '<span class="hl">' + t + '</span>' : t;202 }).join('');203 linesEl.appendChild(lineEl);204 });205 el.appendChild(linesEl);206 }207 stage.appendChild(el);208 });209 const slides = stage.querySelectorAll('.slide');210 let idx = 0;211 function show(i) {212 if (i < 0) i = 0; if (i >= slides.length) i = slides.length - 1;213 slides[idx].classList.remove('active');214 idx = i;215 slides[idx].classList.add('active');216 pager.textContent = String(idx + 1).padStart(2, '0') + ' / ' + String(slides.length).padStart(2, '0');217 body.setAttribute('data-current', slides[idx].getAttribute('data-emphasis') === 'true' ? 'emphasis' : 'theme');218 }219 function next() { show(idx + 1); }220 function prev() { show(idx - 1); }221 document.addEventListener('keydown', (e) => {222 switch (e.key) {223 case 'ArrowRight': case ' ': case 'Enter': case 'j': case 'PageDown': e.preventDefault(); next(); break;224 case 'ArrowLeft': case 'k': case 'PageUp': e.preventDefault(); prev(); break;225 case 'Home': e.preventDefault(); show(0); break;226 case 'End': e.preventDefault(); show(slides.length - 1); break;227 case 'f': case 'F': e.preventDefault(); document.fullscreenElement ? document.exitFullscreen?.() : document.documentElement.requestFullscreen?.(); break;228 }229 });230 let touchX = null;231 document.addEventListener('touchstart', (e) => { touchX = e.touches[0].clientX; });232 document.addEventListener('touchend', (e) => {233 if (touchX == null) return;234 const dx = e.changedTouches[0].clientX - touchX;235 if (dx < -40) next(); else if (dx > 40) prev();236 touchX = null;237 });238 document.addEventListener('click', (e) => {239 if (e.target.closest('.pager,.subtitle')) return;240 const mid = window.innerWidth / 2;241 if (e.clientX > mid) next(); else prev();242 });243 show(0);244</script>245</body>246</html>247```248249【调用流程 — agent 内部】2501. 读用户内容(markdown / outline / 纯文本)2512. 按上面表格做 **outline → slides 数组** 映射, 不抽提不重写2523. 推断 theme(标签 > 语气 > 默认 black)2534. 复用骨架, 替换 `<title>` / `data-theme` / `<div id="subtitle">` 内容 / `SLIDES` 数组2545. 一次性输出整个 HTML 文档255256【品味准则】257- outline 是真理, skill 是渲染器258- 一级标题 = emphasis 封面(天然章节断点)259- 二级标题 = 独占 theme 页(给标题应有的重量)260- 列表错位靠 indent 0/1/2 体现嵌套深度261- `**强调**` 自动 hl262- 拆页保持视觉一致性(同源块字号/缩进对齐)263- 左对齐不居中——这是 manifesto 美学的灵魂264265【禁区】266- 不抽 manifesto(不要"找钉子", 作者已经写好了 outline)267- 不写新句子、不重组顺序、不删内容268- 不放图片 / 不放图标 / 不加过渡动画269- 不在 emphasis 页用 inline hl(emphasis 整页就是高亮)270- 不混用多个 theme(一篇一个气质)271- 不擅自加 emphasis(只有一级标题 / 首末页 / 分隔符)272273【致谢】274本 skill 改编自 [lijigang/ljg-skills · ljg-present](https://github.com/lijigang/ljg-skills/tree/md/skills/ljg-present)(v3.0.0)。原版输出多主题包含 cyber-hacker 模式与 PNG 投影; html-anything 版只保留 3 主题 + 单文件 HTML 输出。审美灵感继续指向 Felipe Franco / BIG STUDIOS 的 manifesto 字体海报。