first-commit
ci / Validate workspace (push) Has been cancelled
landing-page-ci / Validate landing page (push) Has been cancelled
landing-page-deploy / Deploy landing page (push) Has been cancelled
github-metrics / Generate repository metrics SVG (push) Has been cancelled
refresh-contributors-wall / Refresh contributors wall cache bust (push) Waiting to run
ci / Validate workspace (push) Has been cancelled
landing-page-ci / Validate landing page (push) Has been cancelled
landing-page-deploy / Deploy landing page (push) Has been cancelled
github-metrics / Generate repository metrics SVG (push) Has been cancelled
refresh-contributors-wall / Refresh contributors wall cache bust (push) Waiting to run
This commit is contained in:
@@ -0,0 +1,318 @@
|
||||
<!--
|
||||
Example slides for the magazine-web-ppt skill.
|
||||
|
||||
Topic: "一人公司 · The Quiet Hardware" — a fictional but realistic 64-day
|
||||
case study, mirroring the rhythm and content arc of the original 歸藏
|
||||
guizang-ppt-skill demo. Used to power the Examples preview without
|
||||
requiring real product imagery on disk — image slots stand in for what a
|
||||
real deck would show.
|
||||
|
||||
Theme rhythm: hero dark → light → dark → light → hero light → dark →
|
||||
hero dark → light → hero light. Hits all 8 layout categories.
|
||||
-->
|
||||
|
||||
<!-- Layout 1 · Hero Cover ============================================ -->
|
||||
<section class="slide hero dark">
|
||||
<div class="chrome">
|
||||
<div>A Talk · 2026.04.22</div>
|
||||
<div>Vol.01</div>
|
||||
</div>
|
||||
<div class="frame" style="display:grid; gap:4vh; align-content:center; min-height:80vh">
|
||||
<div class="kicker">私享会 · 创作者 Demo Day</div>
|
||||
<h1 class="h-hero">一人公司</h1>
|
||||
<h2 class="h-sub">被 AI 折叠的组织</h2>
|
||||
<p class="lead" style="max-width:60vw">
|
||||
一个独立创作者 —— 在 64 天里完成 11 万行代码、覆盖 9 个平台、跨过 5 个时区,<br>
|
||||
生活节奏几乎没有被打扰。
|
||||
</p>
|
||||
<div class="meta-row">
|
||||
<span>歸藏 Guizang</span><span>·</span><span>独立创作者</span><span>·</span><span>CodePilot 作者</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="foot">
|
||||
<div>一场关于 AI · 组织 · 个体的分享</div>
|
||||
<div>— 2026 —</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- Layout 2 · Big Numbers Grid ======================================= -->
|
||||
<section class="slide light">
|
||||
<div class="chrome">
|
||||
<div>过去 64 天 · 开发篇</div>
|
||||
<div>Act I / Dev · 02 / 09</div>
|
||||
</div>
|
||||
<div class="frame" style="padding-top:6vh">
|
||||
<div class="kicker">一个人,做了什么。</div>
|
||||
<h2 class="h-xl">过去 64 天</h2>
|
||||
<p class="lead" style="margin-bottom:5vh">从 0 到开源 CodePilot。</p>
|
||||
|
||||
<div class="grid-6" style="margin-top:6vh">
|
||||
<div class="stat-card">
|
||||
<div class="stat-label">Duration</div>
|
||||
<div class="stat-nb">64 <span class="stat-unit">天</span></div>
|
||||
<div class="stat-note">从立项到现在</div>
|
||||
</div>
|
||||
<div class="stat-card">
|
||||
<div class="stat-label">Lines of Code</div>
|
||||
<div class="stat-nb">110K+</div>
|
||||
<div class="stat-note">一行一行写到 11 万+</div>
|
||||
</div>
|
||||
<div class="stat-card">
|
||||
<div class="stat-label">GitHub Stars</div>
|
||||
<div class="stat-nb">5,166</div>
|
||||
<div class="stat-note">单仓库 · 60 天破 5K</div>
|
||||
</div>
|
||||
<div class="stat-card">
|
||||
<div class="stat-label">Downloads</div>
|
||||
<div class="stat-nb">41K+</div>
|
||||
<div class="stat-note">装进了几万台电脑里</div>
|
||||
</div>
|
||||
<div class="stat-card">
|
||||
<div class="stat-label">AI Providers</div>
|
||||
<div class="stat-nb">19</div>
|
||||
<div class="stat-note">跨平台模型接入</div>
|
||||
</div>
|
||||
<div class="stat-card">
|
||||
<div class="stat-label">Commits</div>
|
||||
<div class="stat-nb">608+</div>
|
||||
<div class="stat-note">没有协作者</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="foot">
|
||||
<div>项目 · CodePilot | github.com/codepilot</div>
|
||||
<div>Act I · Dev Numbers</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- Layout 4 · Quote + Image ========================================== -->
|
||||
<section class="slide dark">
|
||||
<div class="chrome">
|
||||
<div>身份反差 · The Twist</div>
|
||||
<div>03 / 09</div>
|
||||
</div>
|
||||
<div class="frame grid-2-7-5" style="padding-top:6vh">
|
||||
<div style="display:flex; flex-direction:column; justify-content:space-between; gap:3vh">
|
||||
<div>
|
||||
<div class="kicker">BUT</div>
|
||||
<h2 class="h-xl" style="white-space:nowrap; font-size:7.2vw">
|
||||
我不是程序员。
|
||||
</h2>
|
||||
<p class="lead" style="margin-top:3vh">
|
||||
大学毕业之后再没写过一行生产代码。过去十年做的是 UI 设计 / AI 特效 / 自媒体内容。
|
||||
</p>
|
||||
</div>
|
||||
<div class="callout">
|
||||
“这东西在三年前,<br>
|
||||
需要一个十人团队做一年。”
|
||||
<div class="callout-src">— 一个观察者的判断</div>
|
||||
</div>
|
||||
</div>
|
||||
<figure class="img-slot r-3x2" style="aspect-ratio:16/10; max-height:56vh">
|
||||
<span class="plus">+</span>
|
||||
<span class="label">Product Screenshot · CodePilot</span>
|
||||
</figure>
|
||||
</div>
|
||||
<div class="foot">
|
||||
<div>Page 03 · 我不是程序员</div>
|
||||
<div>— · —</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- Layout 6 · Pipeline =============================================== -->
|
||||
<section class="slide light">
|
||||
<div class="chrome">
|
||||
<div>我的工作流 · Workflow</div>
|
||||
<div>Act II · 04 / 09</div>
|
||||
</div>
|
||||
<div class="frame">
|
||||
<div class="kicker">Pipeline · 流水线</div>
|
||||
<h2 class="h-xl">两条流水线</h2>
|
||||
|
||||
<div class="pipeline-section">
|
||||
<div class="pipeline-label">文本侧 · Text Pipeline</div>
|
||||
<div class="pipeline">
|
||||
<div class="step">
|
||||
<div class="step-nb">01</div>
|
||||
<div class="step-title">Draft</div>
|
||||
<div class="step-desc">AI 帮我起草初稿</div>
|
||||
</div>
|
||||
<div class="step">
|
||||
<div class="step-nb">02</div>
|
||||
<div class="step-title">Polish</div>
|
||||
<div class="step-desc">AI 润色去 AI 味</div>
|
||||
</div>
|
||||
<div class="step">
|
||||
<div class="step-nb">03</div>
|
||||
<div class="step-title">Morph</div>
|
||||
<div class="step-desc">AI 变形成推特 / 小红书</div>
|
||||
</div>
|
||||
<div class="step">
|
||||
<div class="step-nb">04</div>
|
||||
<div class="step-title">Illustrate</div>
|
||||
<div class="step-desc">AI 生成信息图</div>
|
||||
</div>
|
||||
<div class="step">
|
||||
<div class="step-nb">05</div>
|
||||
<div class="step-title">Distribute</div>
|
||||
<div class="step-desc">一键分发 9 平台</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="pipeline-section">
|
||||
<div class="pipeline-label">视觉 · 视频侧 · Video Pipeline</div>
|
||||
<div class="pipeline" data-cols="3">
|
||||
<div class="step">
|
||||
<div class="step-nb">06</div>
|
||||
<div class="step-title">Cut</div>
|
||||
<div class="step-desc">AI 剪辑 + 自动配字幕</div>
|
||||
</div>
|
||||
<div class="step">
|
||||
<div class="step-nb">07</div>
|
||||
<div class="step-title">Wrap</div>
|
||||
<div class="step-desc">AI 包装 + 配 BGM</div>
|
||||
</div>
|
||||
<div class="step">
|
||||
<div class="step-nb">08</div>
|
||||
<div class="step-title">Cover</div>
|
||||
<div class="step-desc">AI 生成封面图</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="foot">
|
||||
<div>Page 04 · 我的内容工厂</div>
|
||||
<div>Workflow</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- Layout 2 · Act Divider ============================================ -->
|
||||
<section class="slide hero light">
|
||||
<div class="chrome">
|
||||
<div>第二幕 · 折叠</div>
|
||||
<div>Act II · 05 / 09</div>
|
||||
</div>
|
||||
<div class="frame" style="display:grid; gap:6vh; align-content:center; min-height:80vh">
|
||||
<div class="kicker">Act II</div>
|
||||
<h1 class="h-hero" style="font-size:8.5vw">折叠</h1>
|
||||
<p class="lead" style="max-width:55vw">
|
||||
从 “一个人做内容” 到 “一个人是组织”。<br>
|
||||
AI 不是工具,是岗位的折叠器。
|
||||
</p>
|
||||
</div>
|
||||
<div class="foot">
|
||||
<div>第二幕引子</div>
|
||||
<div>— · —</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- Layout 8 · Big Quote ============================================== -->
|
||||
<section class="slide dark">
|
||||
<div class="chrome">
|
||||
<div>The Takeaway · 核心金句</div>
|
||||
<div>06 / 09</div>
|
||||
</div>
|
||||
<div class="frame" style="display:grid; gap:5vh; align-content:center; min-height:80vh">
|
||||
<div class="kicker">Quote · 金句</div>
|
||||
<blockquote style="font-family:var(--serif-zh); font-weight:700; font-size:5.6vw; line-height:1.2; letter-spacing:-.01em; max-width:78vw">
|
||||
“没有交接,<br>所有人都在构建。”
|
||||
</blockquote>
|
||||
<p class="lead" style="max-width:55vw; opacity:.65">
|
||||
Without the handoff, everyone builds.<br>
|
||||
And that makes all the difference.
|
||||
</p>
|
||||
<div class="meta-row">
|
||||
<span>— Luke Wroblewski</span><span>·</span><span>2026.04.16</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="foot">
|
||||
<div>Page 06 · 金句</div>
|
||||
<div>— · —</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- Layout 7 · Hero Question ========================================== -->
|
||||
<section class="slide hero dark">
|
||||
<div class="chrome">
|
||||
<div>留给你的问题</div>
|
||||
<div>07 / 09</div>
|
||||
</div>
|
||||
<div class="frame" style="display:grid; gap:8vh; align-content:center; min-height:80vh">
|
||||
<div class="kicker">The Question</div>
|
||||
<h1 class="h-hero" style="font-size:7vw; line-height:1.15">
|
||||
你的公司里,<br>
|
||||
哪些岗位本来就<br>
|
||||
不该由人来做?
|
||||
</h1>
|
||||
<p class="lead" style="max-width:50vw">
|
||||
这不是技术问题,是架构问题。
|
||||
</p>
|
||||
</div>
|
||||
<div class="foot">
|
||||
<div>Page 07 · The Question</div>
|
||||
<div>— · —</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- Layout 9 · Before / After ========================================= -->
|
||||
<section class="slide light">
|
||||
<div class="chrome">
|
||||
<div>旧 vs 新 · The Shift</div>
|
||||
<div>08 / 09</div>
|
||||
</div>
|
||||
<div class="frame" style="padding-top:5vh">
|
||||
<div class="kicker">Before / After · 范式转变</div>
|
||||
<h2 class="h-xl" style="margin-bottom:4vh">从交接到共建</h2>
|
||||
|
||||
<div class="grid-2-6-6" style="gap:5vw 4vh">
|
||||
<div style="padding:3vh 2vw; border-left:3px solid currentColor; opacity:.55">
|
||||
<div class="kicker" style="opacity:.9">Before · 旧模式</div>
|
||||
<h3 class="h-md" style="margin-top:2vh">设计 → 开发 → 交接</h3>
|
||||
<ul style="margin-top:3vh; padding-left:1.2em; display:flex; flex-direction:column; gap:1.4vh; font-family:var(--sans-zh); font-size:max(14px,1.1vw); line-height:1.55">
|
||||
<li>设计师在 Figma 做稿,反复对齐像素</li>
|
||||
<li>开发盯着设计稿手动翻译</li>
|
||||
<li>反复 PR 沟通,文档遗失在 Slack</li>
|
||||
<li>非技术成员无法触碰代码</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div style="padding:3vh 2vw; border-left:3px solid currentColor">
|
||||
<div class="kicker" style="opacity:.9">After · 新模式</div>
|
||||
<h3 class="h-md" style="margin-top:2vh">同工具 · 并行 · 共建</h3>
|
||||
<ul style="margin-top:3vh; padding-left:1.2em; display:flex; flex-direction:column; gap:1.4vh; font-family:var(--sans-zh); font-size:max(14px,1.1vw); line-height:1.55">
|
||||
<li>三个角色同时在同一份 Intent 上工作</li>
|
||||
<li>agents.md / SKILL.md 是共享上下文</li>
|
||||
<li>代理处理对齐、冲突、动效</li>
|
||||
<li>任何人都能安全贡献代码</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="foot">
|
||||
<div>Page 08 · 范式转变</div>
|
||||
<div>Before / After</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- Layout 2 · Hero Close ============================================= -->
|
||||
<section class="slide hero light">
|
||||
<div class="chrome">
|
||||
<div>End · 致谢</div>
|
||||
<div>09 / 09</div>
|
||||
</div>
|
||||
<div class="frame" style="display:grid; gap:5vh; align-content:center; min-height:80vh">
|
||||
<div class="kicker">Thanks for watching</div>
|
||||
<h1 class="h-hero" style="font-size:9vw">谢谢。</h1>
|
||||
<p class="lead" style="max-width:55vw">
|
||||
Slides are a single HTML file —<br>
|
||||
open in any browser, no build, no server.
|
||||
</p>
|
||||
<div class="meta-row">
|
||||
<span>github.com/op7418/guizang-ppt-skill</span><span>·</span><span>MIT License</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="foot">
|
||||
<div>Made with magazine-web-ppt skill</div>
|
||||
<div>— Fin —</div>
|
||||
</div>
|
||||
</section>
|
||||
@@ -0,0 +1,647 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>[必填] 替换为 PPT 标题 · Deck Title</title>
|
||||
<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=Playfair+Display:ital,wght@0,400;0,500;0,600;0,700;0,800;0,900;1,400;1,700&family=Source+Serif+4:ital,opsz,wght@0,8..60,300;0,8..60,400;0,8..60,500;0,8..60,600;1,8..60,400&family=IBM+Plex+Mono:wght@300;400;500;600&family=Noto+Serif+SC:wght@300;400;500;600;700;900&family=Noto+Sans+SC:wght@300;400;500;700;900&display=swap" rel="stylesheet">
|
||||
<style>
|
||||
:root{
|
||||
/* ============ 主题色(默认:🖋 墨水经典) ============
|
||||
切换主题:从 references/themes.md 复制对应的 :root 块
|
||||
整体替换这几行(--ink / --ink-rgb / --paper / --paper-rgb)
|
||||
其他地方散落的 rgba() 都走 var(--ink-rgb) / var(--paper-rgb),无需逐处改 */
|
||||
--ink:#0a0a0b;
|
||||
--ink-rgb:10,10,11;
|
||||
--paper:#f1efea;
|
||||
--paper-rgb:241,239,234;
|
||||
--paper-tint:#e8e5de;
|
||||
--ink-tint:#18181a;
|
||||
|
||||
/* ============ 字体(跨主题固定) ============ */
|
||||
--mono:"IBM Plex Mono",ui-monospace,monospace;
|
||||
--serif-en:"Playfair Display","Source Serif 4",Georgia,serif;
|
||||
--serif-body-en:"Source Serif 4",Georgia,serif;
|
||||
--serif-zh:"Noto Serif SC",source-han-serif-sc,serif;
|
||||
--sans-zh:"Noto Sans SC",source-han-sans-sc,sans-serif;
|
||||
}
|
||||
*{box-sizing:border-box;margin:0;padding:0}
|
||||
html,body{width:100%;height:100%;overflow:hidden;background:var(--ink);color:var(--paper);font-family:var(--sans-zh);-webkit-font-smoothing:antialiased;text-rendering:optimizeLegibility}
|
||||
|
||||
/* ============ WebGL 双背景 ============ */
|
||||
canvas.bg{position:fixed;inset:0;width:100vw;height:100vh;z-index:0;display:block;transition:opacity 1.2s ease}
|
||||
canvas#bg-light{opacity:0}
|
||||
canvas#bg-dark{opacity:1}
|
||||
body.light-bg canvas#bg-light{opacity:1}
|
||||
body.light-bg canvas#bg-dark{opacity:0}
|
||||
|
||||
/* ============ Deck 容器 + 翻页 ============ */
|
||||
/* width: NSLIDES * 100vw,会在 JS 里动态矫正 */
|
||||
#deck{position:fixed;inset:0;width:10000vw;height:100vh;display:flex;flex-wrap:nowrap;transition:transform .9s cubic-bezier(.77,0,.175,1);z-index:10;will-change:transform}
|
||||
.slide{width:100vw;height:100vh;flex:0 0 100vw;position:relative;padding:6vh 6vw 10vh 6vw;display:flex;flex-direction:column;overflow:hidden}
|
||||
.slide.light{color:var(--ink)}
|
||||
.slide.dark{color:var(--paper)}
|
||||
|
||||
/* 默认页:遮罩较厚,保证文字可读 */
|
||||
.slide::before{content:"";position:absolute;inset:0;z-index:-1;pointer-events:none;transition:background .7s ease}
|
||||
.slide.light::before{background:rgba(var(--paper-rgb),.78);backdrop-filter:blur(3px)}
|
||||
.slide.dark::before{background:rgba(var(--ink-rgb),.78);backdrop-filter:blur(3px)}
|
||||
/* Hero 页:遮罩大幅降低,让 WebGL 背景明显透出 */
|
||||
.slide.hero.light::before{background:rgba(var(--paper-rgb),.16);backdrop-filter:none}
|
||||
.slide.hero.dark::before{background:rgba(var(--ink-rgb),.12);backdrop-filter:none}
|
||||
/* Hero 页顶底微弱渐隐,保证 chrome/foot 区域可读 */
|
||||
.slide.hero::after{content:"";position:absolute;inset:0;z-index:-1;pointer-events:none}
|
||||
.slide.hero.light::after{background:linear-gradient(180deg,rgba(var(--paper-rgb),.28) 0%,rgba(var(--paper-rgb),0) 14%,rgba(var(--paper-rgb),0) 86%,rgba(var(--paper-rgb),.28) 100%)}
|
||||
.slide.hero.dark::after{background:linear-gradient(180deg,rgba(var(--ink-rgb),.32) 0%,rgba(var(--ink-rgb),0) 14%,rgba(var(--ink-rgb),0) 86%,rgba(var(--ink-rgb),.32) 100%)}
|
||||
|
||||
/* ============ Magazine chrome:顶部 meta + 底部 foot ============ */
|
||||
.chrome{display:flex;justify-content:space-between;align-items:flex-start;font-family:var(--mono);font-size:12px;letter-spacing:.18em;text-transform:uppercase;opacity:.7}
|
||||
.chrome .left,.chrome .right{display:flex;gap:2.4em;align-items:center}
|
||||
.chrome .sep{width:40px;height:1px;background:currentColor;opacity:.4}
|
||||
.foot{margin-top:auto;display:flex;justify-content:space-between;align-items:flex-end;font-family:var(--mono);font-size:12px;letter-spacing:.14em;text-transform:uppercase;opacity:.55}
|
||||
.foot .title{font-family:var(--serif-zh);font-weight:400;letter-spacing:.05em;text-transform:none;opacity:.75;font-size:13px}
|
||||
|
||||
.tag{display:inline-block;font-family:var(--mono);font-size:11px;letter-spacing:.24em;text-transform:uppercase;padding:6px 14px;border:1px solid currentColor;opacity:.85}
|
||||
.rule{width:100%;height:1px;background:currentColor;opacity:.25;margin:3vh 0}
|
||||
.rule.v{width:1px;height:100%;margin:0}
|
||||
|
||||
/* ============ 字体规则 ============
|
||||
· 衬线(Noto Serif SC / Playfair):大标题、重点金句、数字
|
||||
· 非衬线(Noto Sans SC):正文描述、body、补充说明
|
||||
· 等宽(IBM Plex Mono):kicker、meta 小标签、foot 右侧
|
||||
*/
|
||||
.kicker{font-family:var(--mono);font-size:12px;letter-spacing:.3em;text-transform:uppercase;opacity:.6;margin-bottom:2.6vh}
|
||||
.display{font-family:var(--serif-en);font-weight:700;font-size:11vw;line-height:.92;letter-spacing:-.025em}
|
||||
.display-zh{font-family:var(--serif-zh);font-weight:700;font-size:7.8vw;line-height:1.04;letter-spacing:-.005em}
|
||||
.h1-zh{font-family:var(--serif-zh);font-weight:700;font-size:4.6vw;line-height:1.12;letter-spacing:-.005em}
|
||||
.h2-zh{font-family:var(--serif-zh);font-weight:600;font-size:3.2vw;line-height:1.2;letter-spacing:0}
|
||||
.h3-zh{font-family:var(--serif-zh);font-weight:500;font-size:1.9vw;line-height:1.35}
|
||||
.body-zh{font-family:var(--sans-zh);font-weight:400;font-size:max(15px,1.22vw);line-height:1.75;opacity:.82;letter-spacing:.01em}
|
||||
.body-serif{font-family:var(--serif-zh);font-weight:400;font-size:max(15px,1.3vw);line-height:1.65;opacity:.88}
|
||||
.lead{font-family:var(--serif-zh);font-weight:400;font-size:1.9vw;line-height:1.4;opacity:.85}
|
||||
.meta{font-family:var(--mono);font-size:max(11px,.88vw);letter-spacing:.16em;text-transform:uppercase;opacity:.6}
|
||||
.big-num{font-family:var(--serif-en);font-weight:800;font-size:10vw;line-height:.85;letter-spacing:-.03em;font-feature-settings:"tnum"}
|
||||
.mid-num{font-family:var(--serif-en);font-weight:700;font-size:5.5vw;line-height:.88;letter-spacing:-.02em;font-feature-settings:"tnum"}
|
||||
.ghost{font-family:var(--serif-en);font-weight:900;font-size:34vw;line-height:.8;opacity:.06;letter-spacing:-.04em;position:absolute;font-feature-settings:"tnum"}
|
||||
em{font-style:italic;font-family:var(--serif-en)}
|
||||
.en{font-family:var(--serif-en);font-style:italic;font-weight:500}
|
||||
|
||||
/* ============ 布局工具 ============ */
|
||||
.col{display:flex;flex-direction:column;gap:2.4vh}
|
||||
.row{display:flex;align-items:center;gap:3vw}
|
||||
.grid-6{display:grid;grid-template-columns:repeat(3,1fr);grid-template-rows:repeat(2,1fr);gap:4vw 6vw;flex:1;align-content:center;padding:2vh 0}
|
||||
.grid-9{display:grid;grid-template-columns:repeat(3,1fr);grid-template-rows:repeat(3,1fr);gap:3vh 4vw;flex:1;align-content:center}
|
||||
.grid-4{display:grid;grid-template-columns:repeat(2,1fr);grid-template-rows:repeat(2,1fr);gap:4vh 6vw;flex:1;align-content:center}
|
||||
.grid-3{display:grid;grid-template-columns:repeat(3,1fr);gap:4vw;flex:1;align-content:center}
|
||||
.split{display:grid;grid-template-columns:1fr 1fr;gap:4vw;flex:1;align-items:center}
|
||||
.split-55{display:grid;grid-template-columns:55fr 45fr;gap:5vw;flex:1;align-items:stretch}
|
||||
.fill{flex:1}
|
||||
.center{align-items:center;justify-content:center;text-align:center}
|
||||
.bottom-left{position:absolute;left:6vw;bottom:9vh;max-width:50vw}
|
||||
.bottom-right{position:absolute;right:6vw;bottom:9vh;max-width:50vw;text-align:right}
|
||||
.top-right{position:absolute;right:6vw;top:6vh;text-align:right}
|
||||
|
||||
/* ============ Stat(数字矩阵) ============ */
|
||||
.stat{display:flex;flex-direction:column;gap:1vh;align-items:flex-start}
|
||||
.stat .n{font-family:var(--serif-en);font-weight:800;font-size:8vw;line-height:.88;letter-spacing:-.03em;font-feature-settings:"tnum"}
|
||||
.stat .l{font-family:var(--sans-zh);font-size:max(13px,1.05vw);opacity:.7;margin-top:1vh;font-weight:400;line-height:1.5}
|
||||
.stat .m{font-family:var(--mono);font-size:10px;letter-spacing:.22em;text-transform:uppercase;opacity:.5;margin-bottom:.2vh}
|
||||
|
||||
/* ============ Callout(引用框) ============ */
|
||||
.callout{padding:3vh 2.4vw;border-left:3px solid currentColor;position:relative;font-family:var(--serif-zh);font-size:max(15px,1.2vw);line-height:1.55;opacity:.92}
|
||||
.slide.light .callout{background:rgba(var(--ink-rgb),.05)}
|
||||
.slide.dark .callout{background:rgba(var(--paper-rgb),.06)}
|
||||
.callout .cite{display:block;margin-top:1.6vh;font-family:var(--mono);font-size:11px;letter-spacing:.2em;text-transform:uppercase;opacity:.6}
|
||||
.callout .q-big{font-family:var(--serif-zh);font-weight:600;font-size:max(17px,1.6vw);line-height:1.42}
|
||||
|
||||
/* ============ Platform(平台卡) ============ */
|
||||
.plat{display:flex;flex-direction:column;justify-content:flex-end;padding:2vh 0;border-top:1px solid currentColor;border-color:rgba(127,127,127,.35)}
|
||||
.plat .name{font-family:var(--serif-zh);font-weight:700;font-size:1.8vw;margin-bottom:.6vh}
|
||||
.plat .nb{font-family:var(--serif-en);font-weight:700;font-size:3.2vw;letter-spacing:-.02em;line-height:1;font-feature-settings:"tnum"}
|
||||
.plat .sub{font-family:var(--mono);font-size:10px;letter-spacing:.18em;text-transform:uppercase;opacity:.55;margin-top:.6vh}
|
||||
.plat .fill{font-family:var(--sans-zh);font-weight:300;font-size:2.4vw;opacity:.28;letter-spacing:-.01em;line-height:1}
|
||||
|
||||
/* ============ Rowline(表格行) ============ */
|
||||
.rowline{display:grid;grid-template-columns:1fr 2fr 1fr;gap:2vw;padding:2.2vh 0;border-top:1px solid currentColor;align-items:center;border-color:rgba(127,127,127,.25)}
|
||||
.rowline:last-child{border-bottom:1px solid currentColor;border-color:rgba(127,127,127,.25)}
|
||||
.rowline .k{font-family:var(--serif-zh);font-weight:700;font-size:1.7vw}
|
||||
.rowline .v{font-family:var(--sans-zh);font-weight:400;font-size:max(14px,1.2vw);opacity:.85;line-height:1.55}
|
||||
.rowline .m{font-family:var(--mono);font-size:11px;letter-spacing:.2em;text-transform:uppercase;opacity:.6;justify-self:end}
|
||||
|
||||
/* ============ Pillar(支柱卡片) ============ */
|
||||
.pillar{display:flex;flex-direction:column;gap:1.8vh}
|
||||
.pillar .ic{font-family:var(--serif-en);font-style:italic;font-size:2.6vw;opacity:.45;font-weight:400}
|
||||
.pillar .ic svg{width:2.8vw;height:2.8vw;stroke-width:1.2;opacity:.7}
|
||||
.pillar .t{font-family:var(--serif-zh);font-weight:700;font-size:2.4vw;line-height:1.1}
|
||||
.pillar .d{font-family:var(--sans-zh);font-weight:400;font-size:max(14px,1.1vw);opacity:.76;line-height:1.6}
|
||||
|
||||
/* ============ Signature / Highlight ============ */
|
||||
.sign{font-family:var(--serif-en);font-style:italic;font-weight:500;font-size:2vw;opacity:.7}
|
||||
.hi{position:relative;display:inline}
|
||||
.slide.dark .hi::after{content:"";position:absolute;left:-.1em;right:-.1em;bottom:-.05em;height:.28em;background:rgba(var(--paper-rgb),.15);z-index:-1}
|
||||
.slide.light .hi::after{content:"";position:absolute;left:-.1em;right:-.1em;bottom:-.05em;height:.28em;background:rgba(var(--ink-rgb),.08);z-index:-1}
|
||||
|
||||
/* ============ Icons(Lucide via CDN) ============ */
|
||||
.ico{width:1em;height:1em;display:inline-block;vertical-align:-.12em;stroke:currentColor;fill:none;stroke-width:1.4;stroke-linecap:round;stroke-linejoin:round;flex-shrink:0}
|
||||
.ico-lg,.ico-md,.ico-sm{fill:none;stroke:currentColor;stroke-linecap:round;stroke-linejoin:round}
|
||||
.ico-lg{width:2.6vw;height:2.6vw;stroke-width:1.2;display:inline-block}
|
||||
.ico-md{width:1.8vw;height:1.8vw;stroke-width:1.3;display:inline-block;vertical-align:-.4em}
|
||||
.ico-sm{width:1.1vw;height:1.1vw;stroke-width:1.4;display:inline-block;vertical-align:-.15em;opacity:.7}
|
||||
|
||||
/* ============ 图片占位(虚线框,提示设计师位置) ============ */
|
||||
.img-slot{border:1.5px dashed rgba(127,127,127,.4);display:flex;align-items:center;justify-content:center;flex-direction:column;gap:1vh;padding:2vh 2vw;font-family:var(--mono);font-size:10px;letter-spacing:.28em;text-transform:uppercase;opacity:.55;position:relative;aspect-ratio:16/9;width:100%;max-height:56vh;margin-inline:auto;box-sizing:border-box}
|
||||
.img-slot::before{content:"";position:absolute;inset:8px;border:1px solid currentColor;opacity:.2}
|
||||
.img-slot .plus{font-size:2vw;font-weight:300;opacity:.5;letter-spacing:0}
|
||||
.img-slot .label{position:relative;z-index:2;text-align:center}
|
||||
.img-slot.r-4x3{aspect-ratio:4/3}
|
||||
.img-slot.r-3x2{aspect-ratio:3/2}
|
||||
.img-slot.r-1x1{aspect-ratio:1/1}
|
||||
|
||||
/* ============ 图片实填框(关键:固定高度 + 只裁底部) ============
|
||||
重要约束:高度用内联 height:Nvh 精确控制,不要用 aspect-ratio(会撑破布局)
|
||||
object-position:top center 保证严禁裁剪顶部和左右,只裁剪底部
|
||||
*/
|
||||
.frame-img{overflow:hidden;position:relative;background:rgba(0,0,0,.04);box-sizing:border-box;width:100%;border-radius:4px}
|
||||
.slide.dark .frame-img{background:rgba(255,255,255,.04);border-color:rgba(255,255,255,.12)}
|
||||
.frame-img > img{width:100%;height:100%;object-fit:cover;object-position:top center;display:block}
|
||||
.frame-cap{display:flex;justify-content:space-between;align-items:baseline;gap:1vw;margin-top:.8vh;font-family:var(--mono);font-size:10px;letter-spacing:.22em;text-transform:uppercase;opacity:.72}
|
||||
.frame-cap .pf{font-family:var(--serif-zh);font-weight:600;font-size:max(13px,1vw);letter-spacing:.04em;text-transform:none;opacity:.94}
|
||||
.frame-cap .nb{font-family:var(--serif-en);font-style:italic;font-size:max(15px,1.2vw);letter-spacing:.02em;text-transform:none;opacity:.88}
|
||||
.frame-cap .idx{font-family:var(--mono);opacity:.5}
|
||||
figure.tile{display:flex;flex-direction:column;margin:0;min-width:0}
|
||||
figure.tile > .frame-img{flex:0 0 auto}
|
||||
|
||||
/* ============ 导航 ============ */
|
||||
#nav{position:fixed;left:50%;bottom:2.6vh;transform:translateX(-50%);z-index:30;display:flex;gap:10px;padding:8px 14px;border-radius:999px;background:rgba(0,0,0,.18);backdrop-filter:blur(10px);-webkit-backdrop-filter:blur(10px)}
|
||||
#nav .dot{width:8px;height:8px;border-radius:50%;background:rgba(255,255,255,.3);cursor:pointer;transition:all .3s ease;border:0;padding:0}
|
||||
#nav .dot:hover{background:rgba(255,255,255,.5);transform:scale(1.15)}
|
||||
#nav .dot.active{background:rgba(255,255,255,.95);width:22px;border-radius:999px}
|
||||
body.light-bg #nav{background:rgba(255,255,255,.25)}
|
||||
body.light-bg #nav .dot{background:rgba(var(--ink-rgb),.25)}
|
||||
body.light-bg #nav .dot.active{background:rgba(var(--ink-rgb),.9)}
|
||||
#hint{position:fixed;bottom:3vh;right:3vw;z-index:30;font-family:var(--mono);font-size:10px;letter-spacing:.2em;text-transform:uppercase;opacity:.4;mix-blend-mode:difference;color:#aaa}
|
||||
|
||||
/* ============================================================
|
||||
============ LAYOUTS API · 面向 agent 的类(v2)============
|
||||
所有 layouts.md 中的骨架都基于下面这套命名。
|
||||
如果你在 layouts.md 里看到某个类,它必须在下面有定义。
|
||||
============================================================ */
|
||||
|
||||
/* ---------- .frame:每页主内容容器 ---------- */
|
||||
.frame{flex:1;display:flex;flex-direction:column;min-height:0}
|
||||
/* 当 .frame 同时加了 grid 类时,grid 的 display:grid 覆盖 flex */
|
||||
.frame.grid-2-7-5,
|
||||
.frame.grid-2-6-6,
|
||||
.frame.grid-2-8-4,
|
||||
.frame.grid-3-3,
|
||||
.frame.grid-6{display:grid}
|
||||
|
||||
/* ---------- 标题层级(API 名称,衬线为主) ---------- */
|
||||
.h-hero{
|
||||
font-family:var(--serif-zh);
|
||||
font-weight:900;
|
||||
font-size:10vw;
|
||||
line-height:.96;
|
||||
letter-spacing:-.02em;
|
||||
}
|
||||
.h-xl{
|
||||
font-family:var(--serif-zh);
|
||||
font-weight:700;
|
||||
font-size:6.2vw;
|
||||
line-height:1.08;
|
||||
letter-spacing:-.01em;
|
||||
}
|
||||
.h-sub{
|
||||
font-family:var(--serif-zh);
|
||||
font-weight:500;
|
||||
font-size:3.1vw;
|
||||
line-height:1.25;
|
||||
letter-spacing:0;
|
||||
opacity:.7;
|
||||
}
|
||||
.h-md{
|
||||
font-family:var(--serif-zh);
|
||||
font-weight:600;
|
||||
font-size:2.3vw;
|
||||
line-height:1.3;
|
||||
}
|
||||
/* 英文标题专用(Playfair 衬线) */
|
||||
.h-hero-en,.h-xl-en{font-family:var(--serif-en);letter-spacing:-.025em}
|
||||
|
||||
/* ---------- lead 引语 ---------- */
|
||||
.lead{
|
||||
font-family:var(--serif-zh);
|
||||
font-weight:400;
|
||||
font-size:1.75vw;
|
||||
line-height:1.5;
|
||||
opacity:.86;
|
||||
}
|
||||
|
||||
/* ---------- meta-row 底部元数据 ---------- */
|
||||
.meta-row{
|
||||
display:flex;
|
||||
gap:1.2em;
|
||||
align-items:baseline;
|
||||
flex-wrap:wrap;
|
||||
font-family:var(--mono);
|
||||
font-size:max(12px,.92vw);
|
||||
letter-spacing:.16em;
|
||||
text-transform:uppercase;
|
||||
opacity:.6;
|
||||
}
|
||||
|
||||
/* ---------- stat-card(数据大字报用) ---------- */
|
||||
.stat-card{
|
||||
display:flex;
|
||||
flex-direction:column;
|
||||
gap:.8vh;
|
||||
align-items:flex-start;
|
||||
padding-top:1.6vh;
|
||||
border-top:1px solid currentColor;
|
||||
border-color:rgba(127,127,127,.3);
|
||||
}
|
||||
.stat-card .stat-label{
|
||||
font-family:var(--mono);
|
||||
font-size:max(10px,.78vw);
|
||||
letter-spacing:.24em;
|
||||
text-transform:uppercase;
|
||||
opacity:.55;
|
||||
}
|
||||
.stat-card .stat-nb{
|
||||
font-family:var(--serif-en);
|
||||
font-weight:800;
|
||||
font-size:5.8vw;
|
||||
line-height:.9;
|
||||
letter-spacing:-.03em;
|
||||
font-feature-settings:"tnum";
|
||||
margin-top:.4vh;
|
||||
}
|
||||
.stat-card .stat-nb .stat-unit{
|
||||
font-family:var(--serif-zh);
|
||||
font-weight:500;
|
||||
font-size:.38em;
|
||||
letter-spacing:0;
|
||||
opacity:.72;
|
||||
margin-left:.14em;
|
||||
}
|
||||
.stat-card .stat-note{
|
||||
font-family:var(--sans-zh);
|
||||
font-weight:400;
|
||||
font-size:max(13px,1.05vw);
|
||||
line-height:1.5;
|
||||
opacity:.72;
|
||||
margin-top:.6vh;
|
||||
}
|
||||
/* 当 stat-card 用于 grid-4(2x2),数字可以更大 */
|
||||
.grid-4 .stat-card .stat-nb{font-size:7.5vw}
|
||||
/* 当只有 3 个,字也可以稍大 */
|
||||
.grid-3 .stat-card .stat-nb{font-size:6.8vw}
|
||||
|
||||
/* ---------- pipeline(流水线) ---------- */
|
||||
.pipeline-section{
|
||||
margin-top:4.4vh;
|
||||
padding-top:2.8vh;
|
||||
border-top:1px dashed rgba(127,127,127,.32);
|
||||
}
|
||||
.pipeline-section:first-of-type{
|
||||
border-top:0;
|
||||
padding-top:0;
|
||||
margin-top:3vh;
|
||||
}
|
||||
.pipeline-label{
|
||||
font-family:var(--mono);
|
||||
font-size:max(11px,.85vw);
|
||||
letter-spacing:.24em;
|
||||
text-transform:uppercase;
|
||||
opacity:.62;
|
||||
margin-bottom:2.2vh;
|
||||
}
|
||||
.pipeline{
|
||||
display:grid;
|
||||
grid-template-columns:repeat(5,1fr);
|
||||
gap:1.2vw;
|
||||
}
|
||||
.pipeline[data-cols="3"]{grid-template-columns:repeat(3,1fr)}
|
||||
.pipeline[data-cols="4"]{grid-template-columns:repeat(4,1fr)}
|
||||
.pipeline[data-cols="6"]{grid-template-columns:repeat(6,1fr)}
|
||||
.step{
|
||||
display:flex;
|
||||
flex-direction:column;
|
||||
gap:.8vh;
|
||||
padding-top:1.4vh;
|
||||
border-top:1px solid currentColor;
|
||||
border-color:rgba(127,127,127,.35);
|
||||
}
|
||||
.step-nb{
|
||||
font-family:var(--serif-en);
|
||||
font-style:italic;
|
||||
font-weight:500;
|
||||
font-size:1.15vw;
|
||||
opacity:.45;
|
||||
}
|
||||
.step-title{
|
||||
font-family:var(--sans-zh);
|
||||
font-weight:700;
|
||||
font-size:1.55vw;
|
||||
letter-spacing:.01em;
|
||||
line-height:1.2;
|
||||
}
|
||||
.step-desc{
|
||||
font-family:var(--sans-zh);
|
||||
font-weight:400;
|
||||
font-size:max(12px,.95vw);
|
||||
line-height:1.45;
|
||||
opacity:.72;
|
||||
}
|
||||
|
||||
/* ---------- 网格(layouts.md 所用) ---------- */
|
||||
/* 这些类独立挂到任何容器上都能生效,不依赖 .frame 复合选择器 */
|
||||
.grid-2-7-5{display:grid;grid-template-columns:7fr 5fr;gap:3vw 4vh;align-items:start}
|
||||
.grid-2-6-6{display:grid;grid-template-columns:1fr 1fr;gap:3vw 4vh;align-items:start}
|
||||
.grid-2-8-4{display:grid;grid-template-columns:8fr 4fr;gap:3vw 4vh;align-items:start}
|
||||
.grid-3-3{
|
||||
display:grid;
|
||||
grid-template-columns:repeat(3,1fr);
|
||||
grid-auto-rows:minmax(0,1fr);
|
||||
gap:2.4vh 2vw;
|
||||
}
|
||||
/* grid-6 已在旧样式里定义为 3x2,这里仅补 align */
|
||||
|
||||
/* ---------- 图片 frame-img(layouts.md 主命名) ---------- */
|
||||
/* 在旧样式里已定义,这里补 img-cap 命名别名与增强 */
|
||||
figure.frame-img{margin:0;display:flex;flex-direction:column;min-width:0}
|
||||
.img-cap{
|
||||
display:block;
|
||||
margin-top:.8vh;
|
||||
font-family:var(--mono);
|
||||
font-size:max(10px,.8vw);
|
||||
letter-spacing:.22em;
|
||||
text-transform:uppercase;
|
||||
opacity:.6;
|
||||
}
|
||||
/* callout src 命名别名 */
|
||||
.callout-src{
|
||||
display:block;
|
||||
margin-top:1.6vh;
|
||||
font-family:var(--mono);
|
||||
font-size:11px;
|
||||
letter-spacing:.2em;
|
||||
text-transform:uppercase;
|
||||
opacity:.6;
|
||||
}
|
||||
|
||||
/* ---------- chrome & foot 补位(layouts.md 简单写法) ---------- */
|
||||
.chrome{font-family:var(--mono);font-size:max(11px,.78vw);letter-spacing:.2em;text-transform:uppercase;opacity:.62}
|
||||
.foot{font-family:var(--mono);font-size:max(11px,.78vw);letter-spacing:.18em;text-transform:uppercase;opacity:.5}
|
||||
|
||||
/* ---------- 响应式降级 ---------- */
|
||||
@media (max-width:900px){
|
||||
.display{font-size:16vw}
|
||||
.display-zh{font-size:12vw}
|
||||
.h1-zh{font-size:7vw}
|
||||
.h-hero{font-size:14vw}
|
||||
.h-xl{font-size:9vw}
|
||||
.pipeline{grid-template-columns:repeat(2,1fr)}
|
||||
.grid-2-7-5,.grid-2-6-6,.grid-2-8-4{grid-template-columns:1fr}
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<canvas id="bg-dark" class="bg"></canvas>
|
||||
<canvas id="bg-light" class="bg"></canvas>
|
||||
<div id="hint">← → 翻页 · ESC 索引</div>
|
||||
|
||||
<div id="deck">
|
||||
|
||||
<!-- ============================================================
|
||||
SLIDES 插入区 · 在此处填充所有 <section class="slide ..."> 页面
|
||||
每页模板参考 references/page-patterns.md
|
||||
页面组件参考 references/components.md
|
||||
============================================================ -->
|
||||
|
||||
<!-- SLIDES_HERE -->
|
||||
|
||||
</div>
|
||||
|
||||
<div id="nav"></div>
|
||||
|
||||
<script>
|
||||
/* =============== WebGL 双背景 ===============
|
||||
深色页:Holographic Dispersion(全息色散 · 钛金暗流)—— 彩虹微扰、鼠标径向涟漪
|
||||
浅色页:Spiral Vortex(旋转涡流 · 银色珍珠)—— domain-warp 流动、无中心
|
||||
修改风格请参考 references/webgl-backgrounds.md
|
||||
*/
|
||||
const VS = `attribute vec2 position;void main(){gl_Position=vec4(position,0.0,1.0);}`;
|
||||
|
||||
const FS_DARK = `precision highp float;
|
||||
uniform vec2 u_resolution;uniform float u_time;uniform vec2 u_mouse;
|
||||
vec3 palette(float t,vec3 a,vec3 b,vec3 c,vec3 d){return a+b*cos(6.28318*(c*t+d));}
|
||||
void main(){
|
||||
vec2 uv=gl_FragCoord.xy/u_resolution.xy;
|
||||
vec2 p=uv*2.0-1.0;p.x*=u_resolution.x/u_resolution.y;
|
||||
vec2 m=u_mouse*2.0-1.0;m.x*=u_resolution.x/u_resolution.y;
|
||||
float md=length(p-m);
|
||||
float mr=sin(md*15.0-u_time*4.0)*exp(-md*3.0);p+=mr*0.08;
|
||||
vec2 p0=p;
|
||||
for(float i=1.0;i<4.0;i++){
|
||||
p.x+=0.1/i*sin(i*3.0*p.y+u_time*0.4)+0.05;
|
||||
p.y+=0.1/i*cos(i*2.0*p.x+u_time*0.3)-0.05;
|
||||
}
|
||||
float r=length(p);float ang=atan(p.y,p.x);
|
||||
vec3 a=vec3(0.12,0.12,0.13);
|
||||
vec3 b=vec3(0.03,0.04,0.05);
|
||||
vec3 c=vec3(1.0,1.0,1.0);
|
||||
vec3 d=vec3(0.1,0.2,0.4);
|
||||
vec3 col=palette(r*1.5+p0.x*0.5+u_time*0.1,a,b,c,d);
|
||||
float disp=sin(r*25.0-u_time*1.5+ang*2.0)*0.5+0.5;
|
||||
col+=vec3(disp*0.015,disp*0.01,disp*0.02);
|
||||
float hi=pow(sin(p.x*4.0+p.y*3.0+u_time)*0.5+0.5,8.0);
|
||||
col+=hi*0.08;
|
||||
vec3 base=vec3(0.05,0.05,0.06);
|
||||
col=mix(base,col,0.85);
|
||||
gl_FragColor=vec4(col,1.0);
|
||||
}`;
|
||||
|
||||
const FS_LIGHT = `precision highp float;
|
||||
uniform vec2 u_resolution;uniform float u_time;uniform vec2 u_mouse;
|
||||
float hash(vec2 p){return fract(sin(dot(p,vec2(127.1,311.7)))*43758.5453);}
|
||||
float noise(vec2 p){
|
||||
vec2 i=floor(p),f=fract(p);
|
||||
float a=hash(i),b=hash(i+vec2(1,0));
|
||||
float c=hash(i+vec2(0,1)),d=hash(i+vec2(1,1));
|
||||
vec2 u=f*f*(3.0-2.0*f);
|
||||
return mix(a,b,u.x)+(c-a)*u.y*(1.0-u.x)+(d-b)*u.x*u.y;
|
||||
}
|
||||
float fbm(vec2 p){
|
||||
float v=0.0,a=0.5;
|
||||
mat2 m=mat2(0.80,0.60,-0.60,0.80);
|
||||
for(int i=0;i<5;i++){v+=a*noise(p);p=m*p*2.02;a*=0.5;}
|
||||
return v;
|
||||
}
|
||||
void main(){
|
||||
vec2 uv=gl_FragCoord.xy/u_resolution.xy;
|
||||
vec2 p=uv;p.x*=u_resolution.x/u_resolution.y;
|
||||
vec2 m=u_mouse;m.x*=u_resolution.x/u_resolution.y;
|
||||
vec2 md=p-m;float dl=length(md);
|
||||
p+=normalize(md+vec2(0.0001))*exp(-dl*5.0)*0.03;
|
||||
vec2 q=vec2(fbm(p*1.8+u_time*0.07),fbm(p*1.8+vec2(5.2,1.3)+u_time*0.06));
|
||||
vec2 r=vec2(fbm(p*2.0+q*1.3+vec2(1.7,9.2)+u_time*0.05),
|
||||
fbm(p*2.0+q*1.3+vec2(8.3,2.8)+u_time*0.04));
|
||||
float f=fbm(p*2.2+r*1.5);
|
||||
vec3 silverDark=vec3(0.86,0.85,0.84);
|
||||
vec3 paper=vec3(0.955,0.945,0.925);
|
||||
vec3 col=mix(silverDark,paper,f);
|
||||
float ph=r.x*2.2+u_time*0.35;
|
||||
col+=vec3(0.78,0.62,0.92)*sin(ph)*0.055;
|
||||
col+=vec3(0.55,0.72,0.95)*sin(ph*0.8+2.0)*0.05;
|
||||
float hl=smoothstep(0.48,0.92,f);
|
||||
col+=hl*0.06;
|
||||
gl_FragColor=vec4(col,1.0);
|
||||
}`;
|
||||
|
||||
const mouse={x:0.5,y:0.5};
|
||||
addEventListener('mousemove',e=>{mouse.x=e.clientX/innerWidth;mouse.y=e.clientY/innerHeight});
|
||||
|
||||
function bootGL(canvasId, fsSrc){
|
||||
const canvas=document.getElementById(canvasId);
|
||||
const gl=canvas.getContext('webgl',{alpha:false,antialias:true});
|
||||
if(!gl) return ()=>false;
|
||||
const mk=(t,s)=>{const sh=gl.createShader(t);gl.shaderSource(sh,s);gl.compileShader(sh);return sh};
|
||||
const prog=gl.createProgram();
|
||||
gl.attachShader(prog,mk(gl.VERTEX_SHADER,VS));
|
||||
gl.attachShader(prog,mk(gl.FRAGMENT_SHADER,fsSrc));
|
||||
gl.linkProgram(prog);gl.useProgram(prog);
|
||||
const buf=gl.createBuffer();
|
||||
gl.bindBuffer(gl.ARRAY_BUFFER,buf);
|
||||
gl.bufferData(gl.ARRAY_BUFFER,new Float32Array([-1,-1,1,-1,-1,1,-1,1,1,-1,1,1]),gl.STATIC_DRAW);
|
||||
const pos=gl.getAttribLocation(prog,'position');
|
||||
gl.enableVertexAttribArray(pos);gl.vertexAttribPointer(pos,2,gl.FLOAT,false,0,0);
|
||||
const lRes=gl.getUniformLocation(prog,'u_resolution');
|
||||
const lT=gl.getUniformLocation(prog,'u_time');
|
||||
const lM=gl.getUniformLocation(prog,'u_mouse');
|
||||
const resize=()=>{
|
||||
const d=Math.min(window.devicePixelRatio||1,2);
|
||||
canvas.width=innerWidth*d;canvas.height=innerHeight*d;
|
||||
gl.viewport(0,0,canvas.width,canvas.height);
|
||||
};
|
||||
addEventListener('resize',resize);resize();
|
||||
return (tSec)=>{
|
||||
gl.uniform2f(lRes,canvas.width,canvas.height);
|
||||
gl.uniform1f(lT,tSec);
|
||||
gl.uniform2f(lM,mouse.x,1-mouse.y);
|
||||
gl.drawArrays(gl.TRIANGLES,0,6);
|
||||
return true;
|
||||
};
|
||||
}
|
||||
const drawDark=bootGL('bg-dark',FS_DARK);
|
||||
const drawLight=bootGL('bg-light',FS_LIGHT);
|
||||
const t0=Date.now();
|
||||
(function loop(){
|
||||
const t=(Date.now()-t0)/1000;
|
||||
drawDark(t);drawLight(t);
|
||||
requestAnimationFrame(loop);
|
||||
})();
|
||||
|
||||
// =============== 导航(翻页 / 圆点 / 键盘 / 滚轮 / 触屏) ===============
|
||||
const deck=document.getElementById('deck');
|
||||
const slides=deck.querySelectorAll('.slide');
|
||||
const nav=document.getElementById('nav');
|
||||
let idx=0,total=slides.length,lock=false;
|
||||
|
||||
// 关键:矫正 deck 宽度为 total * 100vw,否则翻页会错位
|
||||
deck.style.width=(total*100)+'vw';
|
||||
|
||||
slides.forEach((s,i)=>{
|
||||
const b=document.createElement('button');
|
||||
b.className='dot';b.dataset.i=i;b.setAttribute('aria-label','Page '+(i+1));
|
||||
b.onclick=()=>go(i);
|
||||
nav.appendChild(b);
|
||||
});
|
||||
|
||||
function go(n){
|
||||
if(lock)return;
|
||||
idx=Math.max(0,Math.min(total-1,n));
|
||||
deck.style.transform=`translateX(${-idx*100}vw)`;
|
||||
/* load-bearing: .slide.active is read by Open Design's host bridge
|
||||
(src/runtime/srcdoc.ts findActiveByClass) to drive the slide counter.
|
||||
No CSS targets it — do not remove. */
|
||||
slides.forEach((s,i)=>s.classList.toggle('active',i===idx));
|
||||
nav.querySelectorAll('.dot').forEach((d,i)=>d.classList.toggle('active',i===idx));
|
||||
/* 主题切换:优先读 data-theme,其次从 class(light/dark)推断 */
|
||||
const el=slides[idx];
|
||||
const th=el.dataset.theme || (el.classList.contains('light')?'light':(el.classList.contains('dark')?'dark':'dark'));
|
||||
document.body.classList.toggle('light-bg',th==='light');
|
||||
lock=true;setTimeout(()=>lock=false,700);
|
||||
}
|
||||
|
||||
/* =============== ESC 索引视图 =============== */
|
||||
let overviewOn=false;
|
||||
const ov=document.createElement('div');
|
||||
ov.id='overview';
|
||||
ov.style.cssText='position:fixed;inset:0;z-index:100;background:rgba(var(--ink-rgb),.92);backdrop-filter:blur(12px);display:none;overflow-y:auto;padding:4vh 4vw';
|
||||
document.body.appendChild(ov);
|
||||
|
||||
function buildOverview(){
|
||||
ov.innerHTML='';
|
||||
const grid=document.createElement('div');
|
||||
grid.style.cssText='display:grid;grid-template-columns:repeat(4,1fr);gap:2vh 1.6vw;max-width:90vw;margin:0 auto';
|
||||
slides.forEach((s,i)=>{
|
||||
const card=document.createElement('div');
|
||||
card.style.cssText='cursor:pointer;border-radius:6px;overflow:hidden;border:2px solid '+(i===idx?'rgba(var(--paper-rgb),.8)':'rgba(var(--paper-rgb),.15)')+';transition:border-color .2s';
|
||||
card.onmouseenter=()=>card.style.borderColor='rgba(var(--paper-rgb),.6)';
|
||||
card.onmouseleave=()=>card.style.borderColor=i===idx?'rgba(var(--paper-rgb),.8)':'rgba(var(--paper-rgb),.15)';
|
||||
const wrap=document.createElement('div');
|
||||
wrap.style.cssText='width:100%;aspect-ratio:16/9;overflow:hidden;position:relative;pointer-events:none;background:'+(s.classList.contains('light')?'var(--paper)':'var(--ink)');
|
||||
const clone=s.cloneNode(true);
|
||||
clone.style.cssText='width:100vw;height:100vh;transform:scale('+(1/4.5)+');transform-origin:top left;position:absolute;top:0;left:0;pointer-events:none';
|
||||
wrap.appendChild(clone);
|
||||
const label=document.createElement('div');
|
||||
label.style.cssText='padding:6px 10px;font-family:var(--mono);font-size:11px;letter-spacing:.18em;text-transform:uppercase;color:var(--paper);opacity:.7';
|
||||
label.textContent=(i+1)+' / '+total;
|
||||
card.appendChild(wrap);
|
||||
card.appendChild(label);
|
||||
card.onclick=()=>{toggleOverview();go(i)};
|
||||
grid.appendChild(card);
|
||||
});
|
||||
ov.appendChild(grid);
|
||||
}
|
||||
|
||||
function toggleOverview(){
|
||||
overviewOn=!overviewOn;
|
||||
if(overviewOn){buildOverview();ov.style.display='block';}
|
||||
else{ov.style.display='none';}
|
||||
}
|
||||
|
||||
addEventListener('keydown',e=>{
|
||||
if(e.key==='Escape'){e.preventDefault();toggleOverview();return;}
|
||||
if(overviewOn)return;
|
||||
if(e.key==='ArrowRight'||e.key==='PageDown'||e.key===' '||e.key==='ArrowDown')go(idx+1);
|
||||
if(e.key==='ArrowLeft'||e.key==='PageUp'||e.key==='ArrowUp')go(idx-1);
|
||||
if(e.key==='Home')go(0);
|
||||
if(e.key==='End')go(total-1);
|
||||
});
|
||||
|
||||
let wheelTO=null,wheelAcc=0;
|
||||
addEventListener('wheel',e=>{
|
||||
wheelAcc+=e.deltaY+e.deltaX;
|
||||
if(Math.abs(wheelAcc)>50){go(idx+(wheelAcc>0?1:-1));wheelAcc=0;}
|
||||
clearTimeout(wheelTO);wheelTO=setTimeout(()=>wheelAcc=0,150);
|
||||
},{passive:true});
|
||||
|
||||
let tx=0,ty=0;
|
||||
addEventListener('touchstart',e=>{tx=e.touches[0].clientX;ty=e.touches[0].clientY},{passive:true});
|
||||
addEventListener('touchend',e=>{
|
||||
const dx=(e.changedTouches[0].clientX-tx);
|
||||
const dy=(e.changedTouches[0].clientY-ty);
|
||||
if(Math.abs(dx)>50&&Math.abs(dx)>Math.abs(dy))go(idx+(dx<0?1:-1));
|
||||
},{passive:true});
|
||||
|
||||
go(0);
|
||||
</script>
|
||||
<script src="https://unpkg.com/lucide@latest/dist/umd/lucide.min.js"></script>
|
||||
<script>lucide.createIcons();</script>
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user