"Helvetica Neue", "Arial Black", "Inter", "PingFang SC", "Heiti SC", "STHeiti", -apple-system, sans-serif
font-weight: 900
输出单文件 HTML, 完全自包含, inline CSS + inline JS, 直接在 iframe sandbox 里能跑。骨架照下面这个模板, 把 SLIDES 数组、<title>、{{SUBTITLE}}、body[data-theme] 填好即可。不要外链 CDN, 不要外部资源。
{ lines: [ { indent: 0, chunks: [ {t: "前段"}, {t: "高亮词", hl: true}, {t: "后段"} ] } ] }
{ emphasis: true, lines: [ { indent: 0, chunks: [ {t: "AI"} ] } ] }
{ emphasis: true, lines: [] }
<!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">
<div class="stage" id="stage"></div>
<div class="pager" id="pager">01 / 01</div>
<div class="subtitle" id="subtitle"></div>
<script>
const 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() {
adj = maxLen + .(, lineCount - ) * ;
(adj <= ) ;
(adj <= ) ;
(adj <= ) ;
(adj <= ) ;
;
}
() {
(s == ? : s)
.(, ).(, )
.(, ).(, ).(, );
}
.( {
el = .();
el. = ;
(s.) el.(, );
(s. && s..) {
el.(, ((s.), s..));
linesEl = .();
linesEl. = ;
s..( {
lineEl = .();
lineEl. = ;
lineEl.(, (line. || ));
lineEl. = (line. || []).( {
t = (c.);
c. ? + t + : t;
}).();
linesEl.(lineEl);
});
el.(linesEl);
}
stage.(el);
});
slides = stage.();
idx = ;
() {
(i < ) i = ; (i >= slides.) i = slides. - ;
slides[idx]..();
idx = i;
slides[idx]..();
pager. = (idx + ).(, ) + + (slides.).(, );
body.(, slides[idx].() === ? : );
}
() { (idx + ); }
() { (idx - ); }
.(, {
(e.) {
: : : : : e.(); (); ;
: : : e.(); (); ;
: e.(); (); ;
: e.(); (slides. - ); ;
: : e.(); . ? .?.() : ..?.(); ;
}
});
touchX = ;
.(, { touchX = e.[].; });
.(, {
(touchX == ) ;
dx = e.[]. - touchX;
(dx < -) (); (dx > ) ();
touchX = ;
});
.(, {
(e..()) ;
mid = . / ;
(e. > mid) (); ();
});
();
</script>
</body>
</html>